diff options
| author | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 20:03:48 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 20:03:48 -0800 |
| commit | a931b32fc32a4c59f711ddea37ed56d414c9ded7 (patch) | |
| tree | 2eb9acf38b04e91065c6920b9d803b4716a75db2 | |
| parent | 70d68bd32041d22febb277038641d55c6ac7b57a (diff) | |
v2.4.7.4 -> v2.4.7.5
- Alan Cox: more merging
- L.C. Chang: new SiS IDE PCI id's.
- Maciej Rozycki: make MP table parsing more anal. Should fix broken P4 MP tables.
- Leonard Zubkoff: merge DAC960 completion changes
- Christoph Rohland: saner tmpfs mount-time limit behaviour (and remount)
- me: buffer.c logic update - faster and hopefully livelock-free
109 files changed, 8512 insertions, 5695 deletions
diff --git a/Documentation/pci.txt b/Documentation/pci.txt index fecbfaf041ac..0fcf90a7aa89 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -80,7 +80,7 @@ Each entry consists of: class_mask of the class are honored during the comparison. driver_data Data private to the driver. -When the driver exits, it just calls pci_deregister_driver() and the PCI layer +When the driver exits, it just calls pci_unregister_driver() and the PCI layer automatically calls the remove hook for all devices handled by the driver. Please mark the initialization and cleanup functions where appropriate diff --git a/Documentation/sound/btaudio b/Documentation/sound/btaudio new file mode 100644 index 000000000000..97f0401eb8cf --- /dev/null +++ b/Documentation/sound/btaudio @@ -0,0 +1,81 @@ + +Intro +===== + +people start bugging me about this with questions, looks like I +should write up some documentation for this beast. That way I +don't have to answer that much mails I hope. Yes, I'm lazy... + + +You might have noticed that the bt878 grabber cards have actually +_two_ PCI functions: + +$ lspci +[ ... ] +00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02) +00:0a.1 Multimedia controller: Brooktree Corporation Bt878 (rev 02) +[ ... ] + +The first does video, it is backward compatible to the bt848. The second +does audio. btaudio is a driver for the second function. It's a sound +driver which can be used for recording sound (and _only_ recording, no +playback). As most TV cards come with a short cable which can be plugged +into your sound card's line-in you probably don't need this driver if all +you want to do is just watching TV... + + +Driver Status +============= + +Still somewhat experimental. The driver should work stable, i.e. it +should'nt crash your box. It might not work as expected, have bugs, +not being fully OSS API compilant, ... + + +Digital audio mode +================== + +The chip knows different modes. Right now you have to pick the one you +want to use at insmod time. Digital audio mode is the default. The +chip gives you 16 bit stereo sound with ~32 kHz sample rate. According +to the specs it should be possible to get up to 48 kHz, but I havn't +figured out yet how this works. The specs are not very verbose :-( + +Lower sample rates are possible too, but the code isn't written yet. +For now you are limited to the fixed 32 kHz. Mono works throuth, the +driver will do that in software for you. + +With my Hauppauge I get clear sound, but I got also reports saying that +digital audio mode does'nt work. Guess Hauppauge connected the msp34xx +output to the bt878's I2S digital audio input port. + + +analog mode (A/D) +================= + +You can tell the driver to use this mode with the insmod option "analog=1". +The chip has three analog inputs. Consequently you'll get a mixer device +to control these. + +The analog mode supports mono only. Both 8 + 16 bit. Both are _signed_ +int, which is uncommon for the 8 bit case. Sample rate range is 119 kHz +to 448 kHz. Yes, the number of digits is correct. The driver supports +downsampling by powers of two, so you can ask for more usual sample rates +like 44 kHz too. + +With my Hauppauge I get noisy sound on the second input (mapped to line2 +by the mixer device). Others get a useable signal on line1. + + +more hints +========== + +/me uses "sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp" +to dump audio data from btaudio (dsp2) to es1730 (dsp,dsp1). + +Have fun, + + Gerd + +-- +Gerd Knorr <kraxel@bytesex.org> diff --git a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST index ee51e9fe37e3..8b7f0369e512 100644 --- a/Documentation/video4linux/bttv/CARDLIST +++ b/Documentation/video4linux/bttv/CARDLIST @@ -53,11 +53,19 @@ bttv.o card=51 - Eagle Wireless Capricorn2 (bt878A) card=52 - Pinnacle PCTV Studio Pro card=53 - Typhoon TView RDS / FM Stereo - card=54 - Livetec 9415 TV + card=54 - Lifetec LT 9415 TV card=55 - BESTBUY Easy TV card=56 - FlyVideo '98/FM card=57 - GrandTec 'Grand Video Capture' card=58 - Phoebe TV Master Only (No FM) + card=59 - TV Capturer + card=60 - MM100PCTV + card=61 - AG Electronics GMV1 + card=62 - BESTBUY Easy TV (bt878) + card=63 - ATI TV-Wonder + card=64 - ATI TV-Wonder VE + card=65 - FlyVideo 2000S + card=66 - Terratec TValueRadio tuner.o type=0 - Temic PAL (4002 FH5) @@ -85,3 +93,9 @@ tuner.o type=22 - Temic PAL/SECAM multi (4046 FM5) type=23 - Philips PAL_DK type=24 - Philips PAL/SECAM multi (FQ1216ME) + type=25 - LG PAL_I+FM (TAPC-I001D) + type=26 - LG PAL_I (TAPC-I701D) + type=27 - LG NTSC+FM (TPI8NSR01F) + type=28 - LG PAL_BG+FM (TPI8PSB01D) + type=29 - LG PAL_BG (TPI8PSB11D) + type=30 - Temic PAL* auto + FM (4009 FN5) diff --git a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options index a941406e8708..6ea97c4c3ea3 100644 --- a/Documentation/video4linux/bttv/Insmod-options +++ b/Documentation/video4linux/bttv/Insmod-options @@ -13,6 +13,9 @@ bttv.o triton1=0/1 for Triton1 compatibility Triton1 is automatically recognized but this might also help with other chipsets + vsfx=0/1 yet another chipset bug compatibility flag + (bt878 docs mentiones via+sis, but no + specific chipsets with that problem). bigendian=n Set the endianness of the gfx framebuffer. Default is native endian. fieldnr=0/1 Count fields. Some TV descrambling software diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README index 3070af143226..ad41af7bbdc8 100644 --- a/Documentation/video4linux/bttv/README +++ b/Documentation/video4linux/bttv/README @@ -21,8 +21,7 @@ CONFIG_I2C=m CONFIG_I2C_ALGOBIT=m CONFIG_VIDEO_DEV=m -The latest bttv version is available here: - http://www.strusel007.de/linux/bttv/ +The latest bttv version is available from http://bytesex.org/bttv/ You'll find Ralphs original (mostly outdated) documentation in the ralphs-doc subdirectory. diff --git a/Documentation/video4linux/bttv/Sound-FAQ b/Documentation/video4linux/bttv/Sound-FAQ index 8a185e18471c..1fbcd42a79c7 100644 --- a/Documentation/video4linux/bttv/Sound-FAQ +++ b/Documentation/video4linux/bttv/Sound-FAQ @@ -109,6 +109,29 @@ out = _out_put bits of the data register (BT848_GPIO_DATA), in = _in_put bits of the data register, i.e. BT848_GPIO_DATA & ~BT848_GPIO_OUT_EN + + +Other elements of the tvcards array +=================================== + +If you are trying to make a new card work you might find it useful to +know what the other elements in the tvcards array are good for: + +video_inputs - # of video inputs the card has +audio_inputs - historical cruft, not used any more. +tuner - which input is the tuner +svhs - which input is svhs (all others are labled composite) +muxsel - video mux, input->registervalue mapping +pll - same as pll= insmod option +tuner_type - same as tuner= insmod option +*_modulename - hint whenever some card needs this or that audio + module loaded to work properly. + +If some config item is specified both from the tvcards array and as +insmod option, the insmod option takes precedence. + + + Good luck, Gerd @@ -117,4 +140,4 @@ Good luck, PS: If you have a new working entry, mail it to me. -- -Gerd Knorr <kraxel@goldbach.in-berlin.de> +Gerd Knorr <kraxel@bytesex.org> diff --git a/MAINTAINERS b/MAINTAINERS index e95b5b73972b..81fb87ca9e8a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -106,6 +106,13 @@ M: p_gortmaker@yahoo.com L: linux-net@vger.kernel.org S: Maintained +A2232 SERIAL BOARD DRIVER +P: Enver Haase +M: ehaase@inf.fu-berlin.de +M: A2232@gmx.net +L: linux-m68k@lists.linux-m68k.org +S: Maintained + ACENIC DRIVER P: Jes Sorensen M: jes@trained-monkey.org @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 8 -EXTRAVERSION =-pre4 +EXTRAVERSION =-pre5 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile index f238d05c5b19..e04c85516416 100644 --- a/arch/i386/boot/Makefile +++ b/arch/i386/boot/Makefile @@ -67,7 +67,7 @@ setup.o: setup.s $(AS) -o $@ $< setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bsetup: bsetup.o $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< @@ -76,7 +76,7 @@ bsetup.o: bsetup.s $(AS) -o $@ $< bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ dep: diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 69f60775abad..6a14c8c5cd35 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -44,7 +44,6 @@ * */ -#define __ASSEMBLY__ #include <linux/config.h> #include <asm/segment.h> #include <linux/version.h> diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index ebd620a71b43..25220e75cad3 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -273,24 +273,26 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) int count=sizeof(*mpc); unsigned char *mpt=((unsigned char *)mpc)+count; - if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) - { + if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) { panic("SMP mptable: bad signature [%c%c%c%c]!\n", mpc->mpc_signature[0], mpc->mpc_signature[1], mpc->mpc_signature[2], mpc->mpc_signature[3]); - return 1; + return 0; } - if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) - { + if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) { panic("SMP mptable: checksum error!\n"); - return 1; + return 0; } - if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) - { - printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec); - return 1; + if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) { + printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n", + mpc->mpc_spec); + return 0; + } + if (!mpc->mpc_lapic) { + printk(KERN_ERR "SMP mptable: null local APIC address!\n"); + return 0; } memcpy(str,mpc->mpc_oem,8); str[8]=0; @@ -358,6 +360,8 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) } } } + if (!num_processors) + printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; } @@ -508,8 +512,12 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - smp_read_mpc((void *)mpf->mpf_physptr); - + if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + smp_found_config = 0; + printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); + printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); + return; + } /* * If there are no explicit MP IRQ entries, then we are * broken. We set up most of the low 16 IO-APIC pins to diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 5f06d3aca3cb..fb39eb06a454 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -20,7 +20,7 @@ #define DAC960_DriverVersion "2.4.10" -#define DAC960_DriverDate "1 February 2001" +#define DAC960_DriverDate "23 July 2001" #include <linux/version.h> @@ -28,6 +28,7 @@ #include <linux/types.h> #include <linux/blk.h> #include <linux/blkdev.h> +#include <linux/completion.h> #include <linux/delay.h> #include <linux/hdreg.h> #include <linux/interrupt.h> @@ -40,7 +41,6 @@ #include <linux/spinlock.h> #include <linux/timer.h> #include <linux/pci.h> -#include <linux/completion.h> #include <asm/io.h> #include <asm/segment.h> #include <asm/uaccess.h> @@ -485,14 +485,14 @@ static void DAC960_PD_QueueCommand(DAC960_Command_T *Command) static void DAC960_ExecuteCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - DECLARE_COMPLETION(Wait); + DECLARE_COMPLETION(Completion); unsigned long ProcessorFlags; - Command->Waiting = &Wait; + Command->Completion = &Completion; DAC960_AcquireControllerLock(Controller, &ProcessorFlags); DAC960_QueueCommand(Command); DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); if (in_interrupt()) return; - wait_for_completion(&Wait); + wait_for_completion(&Completion); } @@ -1317,7 +1317,7 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T *Controller) { DAC960_V1_DCDB_T DCDBs[DAC960_V1_MaxChannels], *DCDB; - Completion_T Wait[DAC960_V1_MaxChannels], *wait; + Completion_T Completions[DAC960_V1_MaxChannels], *Completion; unsigned long ProcessorFlags; int Channel, TargetID; for (TargetID = 0; TargetID < Controller->Targets; TargetID++) @@ -1328,12 +1328,12 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T DAC960_SCSI_Inquiry_T *InquiryStandardData = &Controller->V1.InquiryStandardData[Channel][TargetID]; InquiryStandardData->PeripheralDeviceType = 0x1F; - wait = &Wait[Channel]; - init_completion(wait); + Completion = &Completions[Channel]; + init_completion(Completion); DCDB = &DCDBs[Channel]; DAC960_V1_ClearCommand(Command); Command->CommandType = DAC960_ImmediateCommand; - Command->Waiting = wait; + Command->Completion = Completion; Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB); DCDB->Channel = Channel; @@ -1364,11 +1364,11 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID]; InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - wait = &Wait[Channel]; - wait_for_completion(wait); + Completion = &Completions[Channel]; + wait_for_completion(Completion); if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) continue; - Command->Waiting = wait; + Command->Completion = Completion; DCDB = &DCDBs[Channel]; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber); @@ -1382,7 +1382,7 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T DAC960_AcquireControllerLock(Controller, &ProcessorFlags); DAC960_QueueCommand(Command); DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); - wait_for_completion(wait); + wait_for_completion(Completion); } } return true; @@ -2769,7 +2769,7 @@ static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller, if (Request->cmd == READ) Command->CommandType = DAC960_ReadCommand; else Command->CommandType = DAC960_WriteCommand; - Command->Waiting = Request->waiting; + Command->Completion = Request->waiting; Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev); Command->BlockNumber = Request->sector @@ -2922,13 +2922,10 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command) DAC960_ProcessCompletedBuffer(BufferHeader, true); BufferHeader = NextBufferHeader; } - /* - Wake up requestor for swap file paging requests. - */ - if (Command->Waiting) + if (Command->Completion != NULL) { - complete(Command->Waiting); - Command->Waiting = NULL; + complete(Command->Completion); + Command->Completion = NULL; } add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber); } @@ -2970,10 +2967,10 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command) DAC960_ProcessCompletedBuffer(BufferHeader, false); BufferHeader = NextBufferHeader; } - if (Command->Waiting) + if (Command->Completion != NULL) { - complete(Command->Waiting); - Command->Waiting = NULL; + complete(Command->Completion); + Command->Completion = NULL; } } } @@ -3587,8 +3584,8 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command) } if (CommandType == DAC960_ImmediateCommand) { - complete(Command->Waiting); - Command->Waiting = NULL; + complete(Command->Completion); + Command->Completion = NULL; return; } if (CommandType == DAC960_QueuedCommand) @@ -3929,10 +3926,10 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) DAC960_ProcessCompletedBuffer(BufferHeader, true); BufferHeader = NextBufferHeader; } - if (Command->Waiting) + if (Command->Completion != NULL) { - complete(Command->Waiting); - Command->Waiting = NULL; + complete(Command->Completion); + Command->Completion = NULL; } add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber); } @@ -3974,10 +3971,10 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) DAC960_ProcessCompletedBuffer(BufferHeader, false); BufferHeader = NextBufferHeader; } - if (Command->Waiting) + if (Command->Completion != NULL) { - complete(Command->Waiting); - Command->Waiting = NULL; + complete(Command->Completion); + Command->Completion = NULL; } } } @@ -4531,8 +4528,8 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) } if (CommandType == DAC960_ImmediateCommand) { - complete(Command->Waiting); - Command->Waiting = NULL; + complete(Command->Completion); + Command->Completion = NULL; return; } if (CommandType == DAC960_QueuedCommand) diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index 44339b7c2b23..fa1361541e68 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -2139,6 +2139,7 @@ static char typedef struct buffer_head BufferHeader_T; typedef struct file File_T; typedef struct block_device_operations BlockDeviceOperations_T; +typedef struct completion Completion_T; typedef struct gendisk GenericDiskInfo_T; typedef struct hd_geometry DiskGeometry_T; typedef struct hd_struct DiskPartition_T; @@ -2153,7 +2154,6 @@ typedef unsigned long ProcessorFlags_T; typedef struct pt_regs Registers_T; typedef struct request IO_Request_T; typedef request_queue_t RequestQueue_T; -typedef struct completion Completion_T; typedef struct super_block SuperBlock_T; typedef struct timer_list Timer_T; typedef wait_queue_head_t WaitQueue_T; @@ -2220,7 +2220,7 @@ typedef struct DAC960_Command DAC960_CommandType_T CommandType; struct DAC960_Controller *Controller; struct DAC960_Command *Next; - Completion_T *Waiting; + Completion_T *Completion; unsigned int LogicalDriveNumber; unsigned int BlockNumber; unsigned int BlockCount; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 4e569fa9f90b..b0327f71aa66 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1034,7 +1034,7 @@ static void main_command_interrupt(void) } /* waits for a delay (spinup or select) to pass */ -static int wait_for_completion(unsigned long delay, timeout_fn function) +static int fd_wait_for_completion(unsigned long delay, timeout_fn function) { if (FDCS->reset){ reset_fdc(); /* do the reset during sleep to win time @@ -1392,7 +1392,7 @@ static int fdc_dtr(void) * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) */ FDCS->dtr = raw_cmd->rate & 3; - return(wait_for_completion(jiffies+2UL*HZ/100, + return(fd_wait_for_completion(jiffies+2UL*HZ/100, (timeout_fn) floppy_ready)); } /* fdc_dtr */ @@ -1509,7 +1509,7 @@ static void setup_rw_floppy(void) function = (timeout_fn) setup_rw_floppy; /* wait until the floppy is spinning fast enough */ - if (wait_for_completion(ready_date,function)) + if (fd_wait_for_completion(ready_date,function)) return; } dflags = DRS->flags; @@ -1939,7 +1939,7 @@ static int start_motor(void (*function)(void) ) set_dor(fdc, mask, data); /* wait_for_completion also schedules reset if needed. */ - return(wait_for_completion(DRS->select_date+DP->select_delay, + return(fd_wait_for_completion(DRS->select_date+DP->select_delay, (timeout_fn) function)); } diff --git a/drivers/char/drm/agpsupport.c b/drivers/char/drm/agpsupport.c index 5c61982d5c9b..9c761dd81433 100644 --- a/drivers/char/drm/agpsupport.c +++ b/drivers/char/drm/agpsupport.c @@ -292,8 +292,8 @@ drm_agp_head_t *drm_agp_init(void) case ALI_M1651: head->chipset = "ALi M1651"; break; case SVWRKS_GENERIC: head->chipset = "Serverworks Generic"; break; - case SVWRKS_HE: head->chipset = "Serverworks HE"; - case SVWRKS_LE: head->chipset = "Serverworks LE"; + case SVWRKS_HE: head->chipset = "Serverworks HE"; break; + case SVWRKS_LE: head->chipset = "Serverworks LE"; break; default: head->chipset = "Unknown"; break; } diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 7c10b0ce1758..f9c5a3ff5819 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -884,8 +884,6 @@ static int mxser_write(struct tty_struct *tty, int from_user, if (!tty || !info->xmit_buf || !mxvar_tmp_buf) return (0); - if (from_user) - down(&mxvar_tmp_buf_sem); save_flags(flags); if (from_user) { down(&mxvar_tmp_buf_sem); diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 05a69587eead..7c4d55ae992e 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -113,7 +113,7 @@ static int nvram_open_mode; /* special open modes */ #define NVRAM_EXCL 2 /* opened with O_EXCL */ #define RTC_FIRST_BYTE 14 /* RTC register number of first NVRAM byte */ -#define NVRAM_BYTES 128 /* number of NVRAM bytes */ +#define NVRAM_BYTES 128-RTC_FIRST_BYTE /* number of NVRAM bytes */ static int mach_check_checksum( void ); diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 515bf9dc2535..60b049aa44b5 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1866,10 +1866,10 @@ static int __init riscom8_setup(char *str) __setup("riscom8=", riscom8_setup); #endif -static const char banner[] __initdata = +static char banner[] __initdata = KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin " "1994-1996.\n"; -static const char no_boards_msg[] __initdata = +static char no_boards_msg[] __initdata = KERN_INFO "rc: No RISCom/8 boards detected.\n"; /* diff --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c index e511a15e4251..b314bf6818db 100644 --- a/drivers/char/sbc60xxwdt.c +++ b/drivers/char/sbc60xxwdt.c @@ -178,7 +178,7 @@ static ssize_t fop_write(struct file * file, const char * buf, size_t count, lof char c; if(get_user(c, buf+ofs)) return -EFAULT; - if(buf[ofs] == 'V') + if(c == 'V') wdt_expect_close = 1; } /* Well, anyhow someone wrote to us, we should return that favour */ diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 47cffac538ff..5ec65dd297a0 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -5432,6 +5432,10 @@ static int __init rs_init(void) state->io_type = SERIAL_IO_HUB6; if (state->port && check_region(state->port,8)) continue; +#ifdef CONFIG_MCA + if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus) + continue; +#endif if (state->flags & ASYNC_BOOT_AUTOCONF) autoconfig(state); } diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index ad9b94da2a76..9a31126aa027 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -26,7 +26,6 @@ #include <asm/ptrace.h> -extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern struct list_head super_blocks; @@ -99,12 +98,12 @@ void handle_sysrq(int key, struct pt_regs *pt_regs, case 's': /* S -- emergency sync */ printk("Emergency Sync\n"); emergency_sync_scheduled = EMERG_SYNC; - wakeup_bdflush(0); + wakeup_bdflush(); break; case 'u': /* U -- emergency remount R/O */ printk("Emergency Remount R/O\n"); emergency_sync_scheduled = EMERG_REMOUNT; - wakeup_bdflush(0); + wakeup_bdflush(); break; case 'p': /* P -- show PC */ printk("Show Regs\n"); diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c index 41afe4a503c1..e8f8379254e3 100644 --- a/drivers/ide/sis5513.c +++ b/drivers/ide/sis5513.c @@ -48,7 +48,15 @@ static const struct { { "SiS540", PCI_DEVICE_ID_SI_540, SIS5513_FLAG_ATA_66, }, { "SiS620", PCI_DEVICE_ID_SI_620, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, { "SiS630", PCI_DEVICE_ID_SI_630, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS635", PCI_DEVICE_ID_SI_635, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS640", PCI_DEVICE_ID_SI_640, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS645", PCI_DEVICE_ID_SI_645, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS650", PCI_DEVICE_ID_SI_650, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, { "SiS730", PCI_DEVICE_ID_SI_730, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS735", PCI_DEVICE_ID_SI_735, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS740", PCI_DEVICE_ID_SI_740, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS745", PCI_DEVICE_ID_SI_745, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS750", PCI_DEVICE_ID_SI_750, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, { "SiS5591", PCI_DEVICE_ID_SI_5591, SIS5513_FLAG_ATA_33, }, { "SiS5597", PCI_DEVICE_ID_SI_5597, SIS5513_FLAG_ATA_33, }, { "SiS5600", PCI_DEVICE_ID_SI_5600, SIS5513_FLAG_ATA_33, }, @@ -338,7 +346,15 @@ static int sis5513_tune_chipset (ide_drive_t *drive, byte speed) case PCI_DEVICE_ID_SI_540: case PCI_DEVICE_ID_SI_620: case PCI_DEVICE_ID_SI_630: + case PCI_DEVICE_ID_SI_635: + case PCI_DEVICE_ID_SI_640: + case PCI_DEVICE_ID_SI_645: + case PCI_DEVICE_ID_SI_650: case PCI_DEVICE_ID_SI_730: + case PCI_DEVICE_ID_SI_735: + case PCI_DEVICE_ID_SI_740: + case PCI_DEVICE_ID_SI_745: + case PCI_DEVICE_ID_SI_750: unmask = 0xF0; four_two = 0x01; break; @@ -423,7 +439,15 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) if (host_dev) { switch(host_dev->device) { + case PCI_DEVICE_ID_SI_635: + case PCI_DEVICE_ID_SI_640: + case PCI_DEVICE_ID_SI_645: + case PCI_DEVICE_ID_SI_650: case PCI_DEVICE_ID_SI_730: + case PCI_DEVICE_ID_SI_735: + case PCI_DEVICE_ID_SI_740: + case PCI_DEVICE_ID_SI_745: + case PCI_DEVICE_ID_SI_750: ultra_100 = 1; case PCI_DEVICE_ID_SI_530: case PCI_DEVICE_ID_SI_540: @@ -598,7 +622,15 @@ unsigned int __init ata66_sis5513 (ide_hwif_t *hwif) case PCI_DEVICE_ID_SI_540: case PCI_DEVICE_ID_SI_620: case PCI_DEVICE_ID_SI_630: + case PCI_DEVICE_ID_SI_635: + case PCI_DEVICE_ID_SI_640: + case PCI_DEVICE_ID_SI_645: + case PCI_DEVICE_ID_SI_650: case PCI_DEVICE_ID_SI_730: + case PCI_DEVICE_ID_SI_735: + case PCI_DEVICE_ID_SI_740: + case PCI_DEVICE_ID_SI_745: + case PCI_DEVICE_ID_SI_750: ata66 = (reg48h & mask) ? 0 : 1; default: break; @@ -625,7 +657,15 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif) case PCI_DEVICE_ID_SI_540: case PCI_DEVICE_ID_SI_620: case PCI_DEVICE_ID_SI_630: + case PCI_DEVICE_ID_SI_635: + case PCI_DEVICE_ID_SI_640: + case PCI_DEVICE_ID_SI_645: + case PCI_DEVICE_ID_SI_650: case PCI_DEVICE_ID_SI_730: + case PCI_DEVICE_ID_SI_735: + case PCI_DEVICE_ID_SI_740: + case PCI_DEVICE_ID_SI_745: + case PCI_DEVICE_ID_SI_750: case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: case PCI_DEVICE_ID_SI_5591: diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 26baf1d8f438..edfdf276b062 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -353,7 +353,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, } if (ackcode != ACK_PENDING || !packet->expect_response) { - packet->state = complete; + packet->state = completed; up(&packet->state_change); up(&packet->state_change); run_task_queue(&packet->complete_tq); @@ -506,7 +506,7 @@ void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data, break; } - packet->state = complete; + packet->state = completed; up(&packet->state_change); run_task_queue(&packet->complete_tq); } @@ -726,7 +726,7 @@ void abort_requests(struct hpsb_host *host) while (lh != &llist) { packet = list_entry(lh, struct hpsb_packet, list); lh = lh->next; - packet->state = complete; + packet->state = completed; packet->ack_code = ACKX_ABORTED; up(&packet->state_change); run_task_queue(&packet->complete_tq); @@ -771,7 +771,7 @@ void abort_timedouts(struct hpsb_host *host) while (lh != &expiredlist) { packet = list_entry(lh, struct hpsb_packet, list); lh = lh->next; - packet->state = complete; + packet->state = completed; packet->ack_code = ACKX_TIMEOUT; up(&packet->state_change); run_task_queue(&packet->complete_tq); diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index d1130307b91d..87762aee898a 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -24,11 +24,11 @@ struct hpsb_packet { /* Okay, this is core internal and a no care for hosts. * queued = queued for sending * pending = sent, waiting for response - * complete = processing completed, successful or not + * completed = processing completed, successful or not * incoming = incoming packet */ enum { - unused, queued, pending, complete, incoming + unused, queued, pending, completed, incoming } __attribute__((packed)) state; /* These are core internal. */ diff --git a/drivers/media/radio/Config.in b/drivers/media/radio/Config.in index b5fb0c2c53a0..864eec2b4a1d 100644 --- a/drivers/media/radio/Config.in +++ b/drivers/media/radio/Config.in @@ -21,6 +21,7 @@ dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi +dep_tristate ' GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV dep_tristate ' miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index fef1dbfb0d13..ed1b138de796 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o +obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c new file mode 100644 index 000000000000..895ad4adbba7 --- /dev/null +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -0,0 +1,451 @@ +/* + *************************************************************************** + * + * radio-gemtek-pci.c - Gemtek PCI Radio driver + * (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru> + * + *************************************************************************** + * + * 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. + * + *************************************************************************** + * + * Gemtek Corp still silently refuses to release any specifications + * of their multimedia devices, so the protocol still has to be + * reverse engineered. + * + * The v4l code was inspired by Jonas Munsin's Gemtek serial line + * radio device driver. + * + * Please, let me know if this piece of code was useful :) + * + * TODO: multiple device support and portability were not tested + * + *************************************************************************** + */ + +#include <linux/version.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/videodev.h> +#include <linux/errno.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#ifndef PCI_VENDOR_ID_GEMTEK +#define PCI_VENDOR_ID_GEMTEK 0x5046 +#endif + +#ifndef PCI_DEVICE_ID_GEMTEK_PR103 +#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001 +#endif + +#ifndef GEMTEK_PCI_RANGE_LOW +#define GEMTEK_PCI_RANGE_LOW (87*16000) +#endif + +#ifndef GEMTEK_PCI_RANGE_HIGH +#define GEMTEK_PCI_RANGE_HIGH (108*16000) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +struct gemtek_pci_card { + struct video_device *videodev; + + u32 iobase; + u32 length; + u8 chiprev; + u16 model; + + u32 current_frequency; + u8 mute; +}; + +static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $"; + +static int nr_radio = -1; + +static int gemtek_pci_open( struct video_device *dev, int flags) +{ + struct gemtek_pci_card *card = dev->priv; + +/* Paranoid check */ + if ( !card ) + return -ENODEV; + + return 0; +} + +static void gemtek_pci_close( struct video_device *dev ) +{ +/* + * The module usage is managed by 'videodev' + */ +} + +static inline u8 gemtek_pci_out( u16 value, u32 port ) +{ + outw( value, port ); + + return (u8)value; +} + +#define _b0( v ) *((u8 *)&v) +static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep ) +{ + register u8 byte = *last_byte; + + if ( !value ) { + if ( !keep ) + value = (u16)port; + byte &= 0xfd; + } else + byte |= 2; + + _b0( value ) = byte; + outw( value, port ); + byte |= 1; + _b0( value ) = byte; + outw( value, port ); + byte &= 0xfe; + _b0( value ) = byte; + outw( value, port ); + + *last_byte = byte; +} + +static inline void gemtek_pci_nil( u32 port, u8 *last_byte ) +{ + __gemtek_pci_cmd( 0x00, port, last_byte, FALSE ); +} + +static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte ) +{ + __gemtek_pci_cmd( cmd, port, last_byte, TRUE ); +} + +static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency ) +{ + register int i; + register u32 value = frequency / 200 + 856; + register u16 mask = 0x8000; + u8 last_byte; + u32 port = card->iobase; + + last_byte = gemtek_pci_out( 0x06, port ); + + i = 0; + do { + gemtek_pci_nil( port, &last_byte ); + i++; + } while ( i < 9 ); + + i = 0; + do { + gemtek_pci_cmd( value & mask, port, &last_byte ); + mask >>= 1; + i++; + } while ( i < 16 ); + + outw( 0x10, port ); +} + + +static inline void gemtek_pci_mute( struct gemtek_pci_card *card ) +{ + outb( 0x1f, card->iobase ); + card->mute = TRUE; +} + +static inline void gemtek_pci_unmute( struct gemtek_pci_card *card ) +{ + if ( card->mute ) { + gemtek_pci_setfrequency( card, card->current_frequency ); + card->mute = FALSE; + } +} + +static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card ) +{ + return ( inb( card->iobase ) & 0x08 ) ? 0 : 1; +} + +static int gemtek_pci_ioctl( struct video_device *dev, unsigned int cmd, void *arg) +{ + struct gemtek_pci_card *card = dev->priv; + + switch ( cmd ) { + case VIDIOCGCAP: + { + struct video_capability c; + + c.type = VID_TYPE_TUNER; + c.channels = 1; + c.audios = 1; + c.maxwidth = 0; + c.maxheight = 0; + c.minwidth = 0; + c.minheight = 0; + strcpy( c.name, "Gemtek PCI Radio" ); + if ( copy_to_user( arg, &c, sizeof( c ) ) ) + return -EFAULT; + + return 0; + } + + case VIDIOCGTUNER: + { + struct video_tuner t; + + if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) ) + return -EFAULT; + + if ( t.tuner ) + return -EINVAL; + + t.rangelow = GEMTEK_PCI_RANGE_LOW; + t.rangehigh = GEMTEK_PCI_RANGE_HIGH; + t.flags = VIDEO_TUNER_LOW; + t.mode = VIDEO_MODE_AUTO; + t.signal = 0xFFFF * gemtek_pci_getsignal( card ); + strcpy( t.name, "FM" ); + + if ( copy_to_user( arg, &t, sizeof( struct video_tuner ) ) ) + return -EFAULT; + + return 0; + } + + case VIDIOCSTUNER: + { + struct video_tuner t; + + if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) ) + return -EFAULT; + + if ( t.tuner ) + return -EINVAL; + + return 0; + } + + case VIDIOCGFREQ: + return put_user( card->current_frequency, (u32 *)arg ); + + case VIDIOCSFREQ: + { + u32 frequency; + + if ( get_user( frequency, (u32 *)arg ) ) + return -EFAULT; + + if ( (frequency < GEMTEK_PCI_RANGE_LOW) || (frequency > GEMTEK_PCI_RANGE_HIGH) ) + return -EINVAL; + + gemtek_pci_setfrequency( card, frequency ); + card->current_frequency = frequency; + card->mute = FALSE; + + return 0; + } + + case VIDIOCGAUDIO: + { + struct video_audio a; + + memset( &a, 0, sizeof( a ) ); + a.flags |= VIDEO_AUDIO_MUTABLE; + a.volume = 1; + a.step = 65535; + strcpy( a.name, "Radio" ); + + if ( copy_to_user( arg, &a, sizeof( struct video_audio ) ) ) + return -EFAULT; + + return 0; + } + + case VIDIOCSAUDIO: + { + struct video_audio a; + + if ( copy_from_user( &a, arg, sizeof( struct video_audio ) ) ) + return -EFAULT; + + if ( a.audio ) + return -EINVAL; + + if ( a.flags & VIDEO_AUDIO_MUTE ) + gemtek_pci_mute( card ); + + else + gemtek_pci_unmute( card ); + + return 0; + } + + default: + return -ENOIOCTLCMD; + } +} + +enum { + GEMTEK_PR103 +}; + +static char *card_names[] __devinitdata = { + "GEMTEK_PR103" +}; + +static struct pci_device_id gemtek_pci_id[] = +{ + { PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 }, + { 0 } +}; + +MODULE_DEVICE_TABLE( pci, gemtek_pci_id ); + +static u8 mx = 1; + +static char gemtek_pci_videodev_name[] = "Gemtek PCI Radio"; + +static inline void gemtek_pci_init_struct( struct video_device *dev ) +{ + memset( dev, 0, sizeof( struct video_device ) ); + dev->owner = THIS_MODULE; + strcpy( dev->name , gemtek_pci_videodev_name ); + dev->type = VID_TYPE_TUNER; + dev->hardware = VID_HARDWARE_GEMTEK; + dev->open = gemtek_pci_open; + dev->close = gemtek_pci_close; + dev->ioctl = gemtek_pci_ioctl; +} + +static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) +{ + struct gemtek_pci_card *card; + struct video_device *devradio; + + if ( (card = kmalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) { + printk( KERN_ERR "gemtek_pci: out of memory\n" ); + return -ENOMEM; + } + memset( card, 0, sizeof( struct gemtek_pci_card ) ); + + if ( pci_enable_device( pci_dev ) ) + goto err_pci; + + card->iobase = pci_resource_start( pci_dev, 0 ); + card->length = pci_resource_len( pci_dev, 0 ); + + if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) { + printk( KERN_ERR "gemtek_pci: i/o port already in use\n" ); + goto err_pci; + } + + pci_read_config_byte( pci_dev, PCI_REVISION_ID, &card->chiprev ); + pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model ); + + pci_set_drvdata( pci_dev, card ); + + if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) { + printk( KERN_ERR "gemtek_pci: out of memory\n" ); + goto err_video; + } + gemtek_pci_init_struct( devradio ); + + if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) { + kfree( devradio ); + goto err_video; + } + + card->videodev = devradio; + devradio->priv = card; + gemtek_pci_mute( card ); + + printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", + card->chiprev, card->iobase, card->iobase + card->length - 1 ); + + return 0; + +err_video: + release_region( card->iobase, card->length ); + +err_pci: + kfree( card ); + return -ENODEV; +} + +static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev ) +{ + struct gemtek_pci_card *card = pci_get_drvdata( pci_dev ); + + video_unregister_device( card->videodev ); + kfree( card->videodev ); + + release_region( card->iobase, card->length ); + + if ( mx ) + gemtek_pci_mute( card ); + + kfree( card ); + + pci_set_drvdata( pci_dev, NULL ); +} + +static struct pci_driver gemtek_pci_driver = +{ + name: "gemtek_pci", +id_table: gemtek_pci_id, + probe: gemtek_pci_probe, + remove: gemtek_pci_remove +}; + +static int __init gemtek_pci_init_module( void ) +{ + return pci_module_init( &gemtek_pci_driver ); +} + +static void __exit gemtek_pci_cleanup_module( void ) +{ + return pci_unregister_driver( &gemtek_pci_driver ); +} + +MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" ); +MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" ); +MODULE_PARM( mx, "b" ); +MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" ); +MODULE_PARM( nr_radio, "i"); +MODULE_PARM_DESC( nr_radio, "video4linux device number to use"); + +EXPORT_NO_SYMBOLS; + +module_init( gemtek_pci_init_module ); +module_exit( gemtek_pci_cleanup_module ); + diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index c3a51d3e261d..f65dfe0d79f6 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -30,7 +30,7 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/mm.h> #include <linux/pci.h> #include <linux/signal.h> diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index 5a4f380d97ba..ecb3cc56f0e9 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -31,7 +31,7 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/kernel.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/mm.h> #include <linux/pci.h> #include <linux/signal.h> diff --git a/drivers/media/video/bt848.h b/drivers/media/video/bt848.h index 340accf31a8b..b51f5b9f7b0d 100644 --- a/drivers/media/video/bt848.h +++ b/drivers/media/video/bt848.h @@ -351,5 +351,6 @@ #define BT878_DEVCTRL 0x40 #define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 #endif diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index bd27d9f8e74a..cd38c6215c92 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c @@ -32,7 +32,7 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/mm.h> #include <linux/pci.h> #include <linux/signal.h> diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 9b37527f47a2..6a41c644f9f7 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -46,13 +46,16 @@ static void init_tea5757(struct bttv *btv); #endif static void winview_audio(struct bttv *btv, struct video_audio *v, int set); +static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set); static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); +static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); /* config variables */ static int triton1=0; +static int vsfx=0; int no_overlay=-1; static unsigned int card[4] = { -1, -1, -1, -1 }; static unsigned int pll[4] = { -1, -1, -1, -1 }; @@ -111,38 +114,55 @@ static struct CARD { int cardnr; char *name; } cards[] __devinitdata = { - { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, - { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00021461, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, - { 0x00031002, BTTV_HAUPPAUGE878, "ATI TV Wonder/VE" }, - { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" }, - { 0x010114c7, 16 /* FIXME */, "Modular Technology PCTV" }, - { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, - { 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" }, - { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV/Radio+" }, - { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" }, - { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" }, - { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" }, - { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" }, + { 0x45000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV/PVR" }, + { 0xff000070, BTTV_HAUPPAUGE878, "Osprey-100" }, + { 0xff010070, BTTV_HAUPPAUGE878, "Osprey-200" }, + + { 0x00011002, BTTV_ATI_TVWONDER, "ATI TV Wonder" }, + { 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" }, + + { 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, { 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" }, + { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCV3/PCI" }, + { 0x405010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCV4/PCI" }, + { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x3000121a, 0/* no entry yet */,"VoodooTV 200" }, + { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" }, - { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" }, + + { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00021461, BTTV_AVERMEDIA98, "AVermedia TVCapture 98" }, + { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" }, + + { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, - { 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" }, + + { 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue" }, + { 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue" }, + { 0x1119153b, BTTV_TERRATVALUE, "Terratec TValue" }, + { 0x111a153b, BTTV_TERRATVALUE, "Terratec TValue" }, + { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV Radio+" }, + { 0x1127153b, BTTV_TERRATV, "Terratec TV+" }, + { 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue" }, + { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, + { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, { 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, - { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCV3/PCI" }, - { 0xff000070, BTTV_HAUPPAUGE878, "Osprey-100" }, - { 0xff010070, BTTV_HAUPPAUGE878, "Osprey-200" }, -#if 0 /* probably wrong */ - { 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, - { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, -#endif + + { 0x010115cb, BTTV_GMV1, "AG GMV1" }, + { 0x010114c7, 16 /* FIXME */, "Modular Technology PCTV" }, + { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" }, + { 0x18511851, 0 /* FIXME */, "CyberMail AV" }, + { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" }, + { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, + { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV" }, + { 0, -1, NULL } }; @@ -223,13 +243,10 @@ struct tvcard bttv_tvcards[] = { audio_inputs: 1, tuner: 0, svhs: 3, - /* old - gpiomask: 15, - audiomux: {12, 4,11,11, 0}, - */ muxsel: { 2, 3, 1, 1}, gpiomask: 0x0f, - audiomux: { 0x04, 0x04, 0x08, 0x04, 0}, + audiomux: { 0x0c, 0x04, 0x08, 0x04, 0}, + /* 0x04 for some cards ?? */ needs_tvaudio: 1, tuner_type: -1, audio_hook: avermedia_tvphone_audio, @@ -286,9 +303,9 @@ struct tvcard bttv_tvcards[] = { audio_inputs: 1, tuner: 0, svhs: 2, - gpiomask: 0x3000f, + gpiomask: 0x3014f, muxsel: { 2, 3, 1, 1}, - audiomux: { 1,0x10001, 0, 0,10}, + audiomux: { 0x20001,0x10001, 0, 0,10}, needs_tvaudio: 1, tuner_type: -1, },{ @@ -490,7 +507,7 @@ struct tvcard bttv_tvcards[] = { muxsel: { 2, 3, 1, 1}, audiomux: { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000}, needs_tvaudio: 1, - tuner_type: -1, + tuner_type: TUNER_PHILIPS_PAL, audio_hook: terratv_audio, },{ /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */ @@ -556,12 +573,13 @@ struct tvcard bttv_tvcards[] = { audio_inputs: 1, tuner: 0, svhs: 2, - gpiomask: 0xfff000, + gpiomask: 0xc33000, muxsel: { 2, 3, 1, 1,0}, - audiomux: { 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000}, - needs_tvaudio: 1, + audiomux: { 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000}, + needs_tvaudio: 0, pll: PLL_28, tuner_type: -1, + audio_hook: winfast2000_audio, },{ name: "Chronos Video Shuttle II", video_inputs: 3, @@ -808,7 +826,7 @@ struct tvcard bttv_tvcards[] = { options bttv card=0 pll=1 radio=1 gpiomask=0x18e0 audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff options tuner type=5 */ - name: "Livetec 9415 TV", + name: "Lifetec LT 9415 TV", video_inputs: 4, audio_inputs: 1, tuner: 0, @@ -816,10 +834,15 @@ struct tvcard bttv_tvcards[] = { gpiomask: 0x18e0, muxsel: { 2, 3, 1, 1}, audiomux: { 0x0000,0x0800,0x1000,0x1000,0x18e0 }, + /* 0x0000: Tuner normal stereo + 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) + 0x0880: Tuner A2 stereo */ pll: PLL_28, tuner_type: TUNER_PHILIPS_PAL, + audio_hook: lt9415_audio, },{ - /* Miguel Angel Alvarez <maacruz@navegalia.com> */ + /* Miguel Angel Alvarez <maacruz@navegalia.com> + old Easy TV BT848 version (model CPH031) */ name: "BESTBUY Easy TV", video_inputs: 4, audio_inputs: 1, @@ -830,22 +853,22 @@ struct tvcard bttv_tvcards[] = { audiomux: { 2, 0, 0, 0, 10}, needs_tvaudio: 0, pll: PLL_28, - tuner_type: TUNER_TEMIC_PAL_I, + tuner_type: TUNER_TEMIC_PAL, },{ /* ---- card 0x38 ---------------------------------- */ - /* Gordon Heydon <gjheydon@bigfoot.com */ + /* Gordon Heydon <gjheydon@bigfoot.com ('98) */ name: "FlyVideo '98/FM", video_inputs: 3, audio_inputs: 3, tuner: 0, svhs: 2, gpiomask: 0x1800, - muxsel: { 2, 3, 1, 1}, + muxsel: { 2, 3, 0, 1}, audiomux: { 0, 0x800, 0, 0, 0x1800, 0 }, needs_tvaudio: 1, pll: PLL_28, - tuner_type: -1, + tuner_type: 5, },{ /* This is the ultimate cheapo capture card * just a BT848A on a small PCB! @@ -875,6 +898,112 @@ struct tvcard bttv_tvcards[] = { needs_tvaudio: 1, pll: PLL_NONE, tuner_type: TUNER_TEMIC_4036FY5_NTSC, +},{ + /* Matti Mottus <mottus@physic.ut.ee> */ + name: "TV Capturer", + video_inputs: 4, + audio_inputs: 1, + tuner: 0, + svhs: 2, + gpiomask: 0x03000F, + muxsel: { 2, 3, 1, 0}, + audiomux: { 2,0,0,0,1 }, + pll: PLL_28, + tuner_type: 0, +},{ + +/* ---- card 0x3c ---------------------------------- */ + /* Philip Blundell <philb@gnu.org> */ + name: "MM100PCTV", + video_inputs: 2, + audio_inputs: 2, + gpiomask: 11, + muxsel: { 2, 3, 1, 1}, + audiomux: { 2, 0, 0, 1, 8}, + pll: PLL_NONE, + tuner_type: TUNER_TEMIC_PAL, + +},{ + /* Adrian Cox <adrian@humboldt.co.uk */ + name: "AG Electronics GMV1", + video_inputs: 2, + audio_inputs: 0, + tuner: -1, + svhs: 1, + gpiomask: 0xF, + muxsel: { 2, 2}, + audiomux: { }, + no_msp34xx: 1, + needs_tvaudio: 0, + pll: PLL_28, + tuner_type: -1, +},{ + /* Miguel Angel Alvarez <maacruz@navegalia.com> + new Easy TV BT878 version (model CPH061) + special thanks to Informatica Mieres for providing the card */ + name: "BESTBUY Easy TV (bt878)", + video_inputs: 3, + audio_inputs: 2, + tuner: 0, + svhs: 2, + gpiomask: 0xFF, + muxsel: { 2, 3, 1, 0}, + audiomux: { 1, 0, 4, 4, 9}, + needs_tvaudio: 0, + pll: PLL_28, + tuner_type: TUNER_PHILIPS_PAL, +},{ + /* Lukas Gebauer <geby@volny.cz> */ + name: "ATI TV-Wonder", + video_inputs: 3, + audio_inputs: 1, + tuner: 0, + svhs: 2, + gpiomask: 0xf03f, + muxsel: { 2, 3, 0, 1}, + audiomux: { 0xbffe, 0, 0xbfff, 0, 0xbffe}, + pll: PLL_28, + tuner_type: TUNER_TEMIC_4006FN5_MULTI_PAL, +},{ + +/* ---- card 0x40 ---------------------------------- */ + /* Lukas Gebauer <geby@volny.cz> */ + name: "ATI TV-Wonder VE", + video_inputs: 2, + audio_inputs: 1, + tuner: 0, + svhs: -1, + gpiomask: 1, + muxsel: { 2, 3, 0, 1}, + audiomux: { 0, 0, 1, 0, 0}, + no_msp34xx: 1, + pll: PLL_28, + tuner_type: TUNER_TEMIC_4006FN5_MULTI_PAL, +},{ + /* DeeJay <deejay@westel900.net (2000S) */ + name: "FlyVideo 2000S", + video_inputs: 3, + audio_inputs: 3, + tuner: 0, + svhs: 2, + gpiomask: 0x18e0, + muxsel: { 2, 3, 0, 1}, + audiomux: { 0,0x18e0,0x1000,0x1000,0x1080, 0x1080 }, + needs_tvaudio: 1, + pll: PLL_28, + tuner_type: 5, +},{ + name: "Terratec TValueRadio", + video_inputs: 3, + audio_inputs: 1, + tuner: 0, + svhs: 2, + gpiomask: 0xffff00, + muxsel: { 2, 3, 1, 1}, + audiomux: { 0x500, 0x500, 0x300, 0x900, 0x900}, + needs_tvaudio: 1, + pll: PLL_28, + tuner_type: TUNER_PHILIPS_PAL, }}; const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); @@ -1031,6 +1160,14 @@ void __devinit bttv_init_card(struct bttv *btv) btv->mbox_mask = 0x38; } + if (btv->type == BTTV_LIFETEC_9415) { + if (btread(BT848_GPIO_DATA) & 0x4000) + printk("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr); + else + printk("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr); + btv->has_radio=1; + } + /* pll configuration */ if (!(btv->id==848 && btv->revision==0x11)) { /* defaults from card list */ @@ -1149,19 +1286,19 @@ hauppauge_tuner[] __devinitdata = { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, { TUNER_ABSENT, "Philips TD1536" }, { TUNER_ABSENT, "Philips TD1536D" }, - { TUNER_ABSENT, "Philips FMR1236" }, + { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ { TUNER_ABSENT, "Philips FI1256MP" }, { TUNER_ABSENT, "Samsung TCPQ9091P" }, { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, - { TUNER_ABSENT, "Temic 4009FN5" }, + { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, { TUNER_ABSENT, "Philips TD1536D_FH_44"}, - { TUNER_ABSENT, "LG TP18NSR01F"}, - { TUNER_ABSENT, "LG TP18PSB01D"}, - { TUNER_ABSENT, "LG TP18PSB11D"}, - { TUNER_ABSENT, "LG TAPC_l001D"}, - { TUNER_ABSENT, "LG TAPC_l701D"} + { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, + { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, + { TUNER_LG_PAL, "LG TP18PSB11D"}, + { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, + { TUNER_LG_PAL_I, "LG TAPC-I701D"} }; static void __devinit hauppauge_eeprom(struct bttv *btv) @@ -1394,7 +1531,8 @@ void winview_audio(struct bttv *btv, struct video_audio *v, int set) int bits_out, loops, vol, data; if (!set) { - v->mode |= VIDEO_AUDIO_VOLUME; + /* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */ + v->flags |= VIDEO_AUDIO_VOLUME; return; } @@ -1490,6 +1628,37 @@ avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) } } +/* Lifetec 9415 handling */ +static void +lt9415_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (btread(BT848_GPIO_DATA) & 0x4000) { + v->mode = VIDEO_SOUND_MONO; + return; + } + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */ + val = 0x0080; + if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */ + val = 0x0880; + if ((v->mode & VIDEO_SOUND_LANG1) || + (v->mode & VIDEO_SOUND_MONO)) + val = 0; + btaor(val, ~0x0880, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"lt9415"); + } else { + /* autodetect doesn't work with this card :-( */ + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + return; + } +} + + static void terratv_audio(struct bttv *btv, struct video_audio *v, int set) { @@ -1510,6 +1679,31 @@ terratv_audio(struct bttv *btv, struct video_audio *v, int set) } } +static void +winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned long val = 0; + + if (set) { + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + if (v->mode & VIDEO_SOUND_MONO) /* Mono */ + val = 0x420000; + if (v->mode & VIDEO_SOUND_LANG1) /* Mono */ + val = 0x420000; + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x410000; + if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ + val = 0x020000; + if (val) { + btaor(val, ~0x430000, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"winfast2000"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} /* ----------------------------------------------------------------------- */ /* motherboard chipset specific stuff */ @@ -1525,10 +1719,14 @@ void __devinit bttv_check_chipset(void) if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF)) triton1 = 1; + while ((dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, dev))) + vsfx = 1; /* print warnings about quirks found */ if (triton1) printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n"); + if (vsfx) + printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); if (pcipci_fail) { printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n"); @@ -1553,25 +1751,28 @@ int __devinit bttv_handle_chipset(struct bttv *btv) { unsigned char command; - if (!triton1) + if (!triton1 && !vsfx) return 0; - if (bttv_verbose) - printk("bttv%d: enabling 430FX/VP3 compatibilty\n",btv->nr); + if (bttv_verbose) { + if (triton1) + printk("bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr); + if (vsfx && btv->id >= 878) + printk("bttv%d: enabling VSFX\n",btv->nr); + } if (btv->id < 878) { - /* bt848 (mis)uses a bit in the irq mask */ - btv->triton1 = BT848_INT_ETBF; + /* bt848 (mis)uses a bit in the irq mask for etbf */ + if (triton1) + btv->triton1 = BT848_INT_ETBF; } else { /* bt878 has a bit in the pci config space for it */ pci_read_config_byte(btv->dev, BT878_DEVCTRL, &command); - command |= BT878_EN_TBFX; + if (triton1) + command |= BT878_EN_TBFX; + if (vsfx) + command |= BT878_EN_VSFX; pci_write_config_byte(btv->dev, BT878_DEVCTRL, command); - pci_read_config_byte(btv->dev, BT878_DEVCTRL, &command); - if (!(command&BT878_EN_TBFX)) { - printk("bttv: 430FX compatibility could not be enabled\n"); - return -1; - } } return 0; } diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 01555bfe718b..0d78394d5825 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -69,6 +69,7 @@ static unsigned int irq_debug = 0; static unsigned int gbuffers = 2; static unsigned int gbufsize = BTTV_MAX_FBUF; static unsigned int combfilter = 0; +static unsigned int lumafilter = 0; static int video_nr = -1; static int radio_nr = -1; static int vbi_nr = -1; @@ -96,6 +97,7 @@ MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)"); MODULE_PARM(gbufsize,"i"); MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); MODULE_PARM(combfilter,"i"); +MODULE_PARM(lumafilter,"i"); MODULE_PARM(video_nr,"i"); MODULE_PARM(radio_nr,"i"); @@ -699,7 +701,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, vadr+=bl; if((rcmd&(15<<28))==BT848_RISC_WRITE123) { - *((*rp)++)=(kvirt_to_bus(cbadr)); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr)); cbadr+=blcb; *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); cradr+=blcr; @@ -1175,7 +1177,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) return -EBUSY; - if(mp->height < 32 || mp->width < 32) + if(mp->height < 32 || mp->width < 48) return -EINVAL; if (mp->format >= PALETTEFMT_MAX) return -EINVAL; @@ -1391,10 +1393,16 @@ static void bttv_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)dev; unsigned long irq_flags; + int need_wait; down(&btv->lock); btv->user--; spin_lock_irqsave(&btv->s_lock, irq_flags); + need_wait = (-1 != btv->gq_grab); + btv->gq_start = 0; + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; btv->scr_on = 0; btv->risc_cap_odd = 0; btv->risc_cap_even = 0; @@ -1410,7 +1418,7 @@ static void bttv_close(struct video_device *dev) btread(BT848_I2C); /* This fixes the PCI posting delay */ - if (-1 != btv->gq_grab) { + if (need_wait) { /* * This is sucky but right now I can't find a good way to * be sure its safe to free the buffer. We wait 5-6 fields @@ -1504,7 +1512,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) b.audios = bttv_tvcards[btv->type].audio_inputs; b.maxwidth = tvnorms[btv->win.norm].swidth; b.maxheight = tvnorms[btv->win.norm].sheight; - b.minwidth = 32; + b.minwidth = 48; b.minheight = 32; if(copy_to_user(arg,&b,sizeof(b))) return -EFAULT; @@ -1717,13 +1725,11 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCGWIN: { struct video_window vw; - /* Oh for a COBOL move corresponding .. */ + memset(&vw,0,sizeof(vw)); vw.x=btv->win.x; vw.y=btv->win.y; vw.width=btv->win.width; vw.height=btv->win.height; - vw.chromakey=0; - vw.flags=0; if(btv->win.interlace) vw.flags|=VIDEO_WINDOW_INTERLACE; if(copy_to_user(arg,&vw,sizeof(vw))) @@ -2196,6 +2202,10 @@ static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) } case VIDIOCGFREQ: case VIDIOCSFREQ: + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGCHAN: + case VIDIOCSCHAN: case BTTV_VERSION: return bttv_ioctl(dev-2,cmd,arg); case BTTV_VBISIZE: @@ -2290,8 +2300,11 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if(v.tuner||btv->channel) /* Only tuner 0 */ return -EINVAL; strcpy(v.name, "Radio"); - v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */ - v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */ + /* japan: 76.0 MHz - 89.9 MHz + western europe: 87.5 MHz - 108.0 MHz + russia: 65.0 MHz - 108.0 MHz */ + v.rangelow=(int)(65*16); + v.rangehigh=(int)(108*16); v.flags= 0; /* XXX */ v.mode = 0; /* XXX */ bttv_call_i2c_clients(btv,cmd,&v); @@ -2441,20 +2454,22 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags) bt848_dma(btv, 0); } +# define do_video_register(dev,type,nr) video_register_device(dev,type,nr) + static int __devinit init_video_dev(struct bttv *btv) { audio(btv, AUDIO_MUTE, 1); - if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) + if(do_video_register(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) return -1; - if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) + if(do_video_register(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) { video_unregister_device(&btv->video_dev); return -1; } if (btv->has_radio) { - if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) + if(do_video_register(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) { video_unregister_device(&btv->vbi_dev); video_unregister_device(&btv->video_dev); @@ -2491,8 +2506,8 @@ static int __devinit init_bt848(struct bttv *btv) btv->win.interlace=1; btv->win.x=0; btv->win.y=0; - btv->win.width=768; /* 640 */ - btv->win.height=576; /* 480 */ + btv->win.width=320; + btv->win.height=240; btv->win.bpp=2; btv->win.depth=16; btv->win.color_fmt=BT848_COLOR_FMT_RGB16; @@ -2542,9 +2557,6 @@ static int __devinit init_bt848(struct bttv *btv) btv->fbuffer=NULL; - bt848_muxsel(btv, 1); - bt848_set_winsize(btv); - /* btwrite(0, BT848_TDEC); */ btwrite(0x10, BT848_COLOR_CTL); btwrite(0x00, BT848_CAP_CTL); @@ -2574,8 +2586,13 @@ static int __devinit init_bt848(struct bttv *btv) btwrite(/*BT848_ADC_SYNC_T|*/ BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC); - btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + if (lumafilter) { + btwrite(0, BT848_E_CONTROL); + btwrite(0, BT848_O_CONTROL); + } else { + btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + } btv->picture.colour=254<<7; btv->picture.brightness=128<<8; @@ -2599,6 +2616,8 @@ static int __devinit init_bt848(struct bttv *btv) BT848_INT_FMTCHG|BT848_INT_HLOCK, BT848_INT_MASK); + bt848_muxsel(btv, 1); + bt848_set_winsize(btv); make_vbitab(btv); spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,-1); @@ -2749,7 +2768,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) wake_up_interruptible(&btv->capq); break; } - if (stat&(8<<28)) + if (stat&(8<<28) && btv->gq_start) { spin_lock(&btv->s_lock); btv->gq_start = 0; diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index 88f26849e944..513c855a45b9 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h @@ -72,9 +72,15 @@ #define BTTV_EAGLE 0x33 #define BTTV_PINNACLEPRO 0x34 #define BTTV_TVIEW_RDS_FM 0x35 -#define BTTV_LIVETEC_9415 0x36 +#define BTTV_LIFETEC_9415 0x36 #define BTTV_BESTBUY_EASYTV 0x37 #define BTTV_FLYVIDEO_98FM 0x38 +#define BTTV_GMV1 0x3d +#define BTTV_BESTBUY_EASYTV2 0x3e +#define BTTV_ATI_TVWONDER 0x3f +#define BTTV_ATI_TVWONDERVE 0x40 +#define BTTV_FLYVIDEO2000 0x41 +#define BTTV_TERRATVALUER 0x42 /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -190,15 +196,12 @@ extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); /* i2c */ #define I2C_CLIENTS_MAX 8 -extern struct i2c_algo_bit_data bttv_i2c_algo_template; -extern struct i2c_adapter bttv_i2c_adap_template; -extern struct i2c_client bttv_i2c_client_template; extern void bttv_bit_setscl(void *data, int state); extern void bttv_bit_setsda(void *data, int state); extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both); + unsigned char b2, int both); extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); #endif /* _BTTV_H_ */ diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index c4af43b32ea7..5dd21de8a642 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -25,7 +25,7 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,57) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,72) #include <linux/types.h> @@ -195,20 +195,8 @@ struct bttv { }; #endif -#if defined(__powerpc__) /* big-endian */ -extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) -{ - __asm__ __volatile__ ("stwbrx %1,0,%2" : \ - "=m" (*addr) : "r" (val), "r" (addr)); - __asm__ __volatile__ ("eieio" : : : "memory"); -} - -#define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat)) -#define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr))) -#else #define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) #define btread(adr) readl(btv->bt848_mem+(adr)) -#endif #define btand(dat,adr) btwrite((dat) & btread(adr), adr) #define btor(dat,adr) btwrite((dat) | btread(adr), adr) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 50aa1a48c5cf..b3d9887b1693 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -57,6 +57,7 @@ #include <linux/unistd.h> #include "audiochip.h" +#include "msp3400.h" /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; @@ -81,6 +82,12 @@ static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), static int simple = -1; /* use short programming (>= msp3410 only) */ static int dolby = 0; +#define DFP_COUNT 0x41 +static const int bl_dfp[] = { + 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a, + 0x0b, 0x0d, 0x0e, 0x10 +}; + struct msp3400c { int simple; int nicam; @@ -90,12 +97,15 @@ struct msp3400c { int nicam_on; int acb; int main, second; /* sound carrier */ - int scart; /* input is scart */ + int scart; /* input is scart (extern) */ int muted; int left, right; /* volume */ int bass, treble; + /* shadow register set */ + int dfp_regs[DFP_COUNT]; + /* thread */ struct task_struct *thread; wait_queue_head_t wq; @@ -525,6 +535,8 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) src = 0x0010 | nicam; break; } + if (msp->scart) + src |= 0x0200; if (dolby) { msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); @@ -534,6 +546,7 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); } } @@ -561,6 +574,19 @@ msp3400c_print_mode(struct msp3400c *msp) } } +static void +msp3400c_restore_dfp(struct i2c_client *client) +{ + struct msp3400c *msp = client->data; + int i; + + for (i = 0; i < DFP_COUNT; i++) { + if (-1 == msp->dfp_regs[i]) + continue; + msp3400c_write(client,I2C_MSP3400C_DFP, i, msp->dfp_regs[i]); + } +} + /* ----------------------------------------------------------------------- */ struct REGISTER_DUMP { @@ -901,8 +927,9 @@ static int msp3400c_thread(void *data) break; } - /* unmute */ + /* unmute + restore dfp registers */ msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp3400c_restore_dfp(client); if (msp->watch_stereo) mod_timer(&msp->wake_stereo, jiffies+5*HZ); @@ -1139,10 +1166,11 @@ static int msp3410d_thread(void *data) break; } - /* unmute */ + /* unmute + restore dfp registers */ msp3400c_setbass(client, msp->bass); msp3400c_settreble(client, msp->treble); msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp3400c_restore_dfp(client); if (msp->watch_stereo) mod_timer(&msp->wake_stereo, jiffies+HZ); @@ -1189,7 +1217,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, DECLARE_MUTEX_LOCKED(sem); struct msp3400c *msp; struct i2c_client *c; - int rev1,rev2=0,i; + int rev1,rev2,i; client_template.adapter = adap; client_template.addr = addr; @@ -1212,6 +1240,9 @@ static int msp_attach(struct i2c_adapter *adap, int addr, msp->right = 65535; msp->bass = 32768; msp->treble = 32768; + for (i = 0; i < DFP_COUNT; i++) + msp->dfp_regs[i] = -1; + c->data = msp; init_waitqueue_head(&msp->wq); @@ -1331,18 +1362,25 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) switch (cmd) { case AUDC_SET_INPUT: -#if 1 + /* scart switching + - IN1 is often used for external input + - Hauppauge uses IN2 for the radio */ dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg); - /* hauppauge 44xxx scart switching */ msp->scart = 0; switch (*sarg) { case AUDIO_RADIO: msp3400c_set_scart(client,SCART_IN2,0); + msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900); + msp3400c_setstereo(client,msp->stereo); break; case AUDIO_EXTERN: - msp->scart = 1; + msp->scart = 1; msp3400c_set_scart(client,SCART_IN1,0); - msp3400c_write(client,I2C_MSP3400C_DFP,0x0008,0x0220); + msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900); + msp3400c_setstereo(client,msp->stereo); + break; + case AUDIO_TUNER: + msp3400c_setstereo(client,msp->stereo); break; default: if (*sarg & AUDIO_MUTE) @@ -1351,7 +1389,6 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) } if (msp->active) msp->restart = 1; -#endif break; case AUDC_SET_RADIO: @@ -1373,6 +1410,33 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) msp->restart = 1; break; +#if 1 + /* work-in-progress: hook to control the DFP registers */ + case MSP_SET_DFPREG: + { + struct msp_dfpreg *r = arg; + int i; + + if (r->reg < 0 || r->reg >= DFP_COUNT) + return -EINVAL; + for (i = 0; i < sizeof(bl_dfp)/sizeof(int); i++) + if (r->reg == bl_dfp[i]) + return -EINVAL; + msp->dfp_regs[r->reg] = r->value; + msp3400c_write(client,I2C_MSP3400C_DFP,r->reg,r->value); + return 0; + } + case MSP_GET_DFPREG: + { + struct msp_dfpreg *r = arg; + + if (r->reg < 0 || r->reg >= DFP_COUNT) + return -EINVAL; + r->value = msp3400c_read(client,I2C_MSP3400C_DFP,r->reg); + return 0; + } +#endif + /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -1443,82 +1507,9 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) break; } - /* --- v4l2 ioctls --- */ - /* NOT YET */ - -#if 0 - /* --- old, obsolete interface --- */ - case AUDC_SET_TVNORM: - msp->norm = *iarg; - break; - case AUDC_SWITCH_MUTE: - /* channels switching step one -- mute */ - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - msp3400c_setvolume(client,0,0); - break; - case AUDC_NEWCHANNEL: - /* channels switching step two -- trigger sound carrier scan */ - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - if (msp->active) - msp->restart = 1; - wake_up_interruptible(&msp->wq); - break; - - case AUDC_GET_VOLUME_LEFT: - *sarg = msp->left; - break; - case AUDC_GET_VOLUME_RIGHT: - *sarg = msp->right; - break; - case AUDC_SET_VOLUME_LEFT: - msp->left = *sarg; - msp3400c_setvolume(client,msp->left, msp->right); - break; - case AUDC_SET_VOLUME_RIGHT: - msp->right = *sarg; - msp3400c_setvolume(client,msp->left, msp->right); - break; - - case AUDC_GET_BASS: - *sarg = msp->bass; - break; - case AUDC_SET_BASS: - msp->bass = *sarg; - msp3400c_setbass(client,msp->bass); - break; - - case AUDC_GET_TREBLE: - *sarg = msp->treble; - break; - case AUDC_SET_TREBLE: - msp->treble = *sarg; - msp3400c_settreble(client,msp->treble); - break; - - case AUDC_GET_STEREO: - autodetect_stereo(client); - *sarg = msp->stereo; - break; - case AUDC_SET_STEREO: - if (*sarg) { - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - msp->stereo = *sarg; - msp3400c_setstereo(client,*sarg); - } - break; - - case AUDC_GET_DC: - if (msp->simple) - break; /* fixme */ - *sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) + - (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c)); - break; -#endif - default:; + default: /* nothing */ + break; } return 0; } diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h new file mode 100644 index 000000000000..9673133f20f7 --- /dev/null +++ b/drivers/media/video/msp3400.h @@ -0,0 +1,14 @@ +#ifndef MSP3400_H +#define MSP3400_H + +/* ---------------------------------------------------------------------- */ + +struct msp_dfpreg { + int reg; + int value; +}; + +#define MSP_SET_DFPREG _IOW('m',15,struct msp_dfpreg) +#define MSP_GET_DFPREG _IOW('m',16,struct msp_dfpreg) + +#endif /* MSP3400_H */ diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index f40e58121c1c..97e2be2b0409 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -5,6 +5,8 @@ * This driver will not complain if used with any * other i2c device with the same address. * + * Muting and tone control by Jonathan Isom <jisom@ematic.com> + * * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com> * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) @@ -16,18 +18,21 @@ * * loudness - set between 0 and 15 for varying degrees of loudness effect * - * TODO: - * Implement tone controls * + * + * Revision: 0.6 - added tone controls + * Revision: 0.5 - Fixed odd balance problem + * Revision: 0.4 - added muting * Revision: 0.3 - Fixed silly reversed volume controls. :) * Revision: 0.2 - Cleaned up #defines * fixed volume control - * Added I2C_DRIVERID_TDA7432 + * Added I2C_DRIVERID_TDA7432 * added loudness insmod control * Revision: 0.1 - initial version */ #include <linux/module.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/string.h> @@ -75,7 +80,7 @@ struct tda7432 { int addr; int input; int volume; - int tone; + int bass, treble; int lf, lr, rf, rr; int loud; struct i2c_client c; @@ -121,7 +126,7 @@ static struct i2c_client client_template; /* Bits 0,1,2 control input: * 0x00 - Stereo input * 0x02 - Mono input - * 0x03 - Mute + * 0x03 - Mute (Using Attenuators Plays better with modules) * Mono probably isn't used - I'm guessing only the stereo * input is connected on most cards, so we'll set it to stereo. * @@ -133,7 +138,6 @@ static struct i2c_client client_template; #define TDA7432_STEREO_IN 0 #define TDA7432_MONO_IN 2 /* Probably won't be used */ -#define TDA7432_MUTE 3 /* Probably won't be used */ #define TDA7432_BASS_SYM 1 << 3 #define TDA7432_BASS_NORM 1 << 4 @@ -178,7 +182,7 @@ static struct i2c_client client_template; #define TDA7432_TREBLE_0DB 0xf #define TDA7432_TREBLE 7 #define TDA7432_TREBLE_GAIN 1 << 3 -#define TDA7432_BASS_0DB 0xf << 4 +#define TDA7432_BASS_0DB 0xf #define TDA7432_BASS 7 << 4 #define TDA7432_BASS_GAIN 1 << 7 @@ -200,6 +204,7 @@ static struct i2c_client client_template; */ #define TDA7432_ATTEN_0DB 0x00 +#define TDA7432_MUTE 0x1 << 5 /* Subaddress 0x07 - Loudness Control */ @@ -257,18 +262,19 @@ static int tda7432_set(struct i2c_client *client) d2printk("tda7432: In tda7432_set\n"); dprintk(KERN_INFO - "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", - t->input,t->volume,t->tone,t->lf,t->lr,t->rf,t->rr,t->loud); + "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud); buf[0] = TDA7432_IN; buf[1] = t->input; buf[2] = t->volume; - buf[3] = t->tone; - buf[4] = t->lf; - buf[5] = t->lr; - buf[6] = t->rf; - buf[7] = t->rr; - buf[8] = t->loud; - if (9 != i2c_master_send(client,buf,9)) { + buf[3] = t->bass; + buf[4] = t->treble; + buf[5] = t->lf; + buf[6] = t->lr; + buf[7] = t->rf; + buf[8] = t->rr; + buf[9] = t->loud; + if (10 != i2c_master_send(client,buf,10)) { printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n"); return -1; } @@ -287,8 +293,8 @@ static void do_tda7432_init(struct i2c_client *client) t->volume = TDA7432_VOL_0DB; /* 0dB Volume */ if (loudness) /* Turn loudness on? */ t->volume |= TDA7432_LD_ON; - t->tone = TDA7432_TREBLE_0DB | /* 0dB Treble */ - TDA7432_BASS_0DB; /* 0dB Bass */ + t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ + t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ @@ -353,9 +359,6 @@ static int tda7432_command(struct i2c_client *client, { struct tda7432 *t = client->data; d2printk("tda7432: In tda7432_command\n"); -#if 0 - __u16 *sarg = arg; -#endif switch (cmd) { /* --- v4l ioctls --- */ @@ -371,7 +374,7 @@ static int tda7432_command(struct i2c_client *client, va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; - + va->mode |= VIDEO_SOUND_STEREO; /* Master volume control * V4L volume is min 0, max 65535 * TDA7432 Volume: @@ -389,18 +392,24 @@ static int tda7432_command(struct i2c_client *client, * attenuation exists for lf, lr, rf, rr * we use only lf and rf (front channels) */ - + if ( (t->lf) < (t->rf) ) /* right is attenuated, balance shifted left */ va->balance = (32768 - 1057*(t->rf)); else /* left is attenuated, balance shifted right */ va->balance = (32768 + 1057*(t->lf)); - - /* Bass/treble */ - va->bass = 32768; /* brain hurts... set to middle for now */ - va->treble = 32768; /* brain hurts... set to middle for now */ + /* Bass/treble */ + va->bass=t->bass; + if(va->bass >= 0x8) + va->bass = ~(va->bass - 0x8) & 0xf; + va->bass = va->bass << 12; + va->treble=t->treble; + if(va->treble >= 0x8) + va->treble = ~(va->treble - 0x8) & 0xf; + va->treble = va->treble << 12; + break; /* VIDIOCGAUDIO case */ } @@ -415,26 +424,65 @@ static int tda7432_command(struct i2c_client *client, if (loudness) /* Turn on the loudness bit */ t->volume |= TDA7432_LD_ON; - if (va->balance < 32768) { + if(va->flags & VIDEO_AUDIO_BASS) + { + t->bass = va->bass >> 12; + if(t->bass>= 0x8) + t->bass = (~t->bass & 0xf) + 0x8 ; + t->bass = t->bass | 0x10; + } + if(va->flags & VIDEO_AUDIO_TREBLE) + { + t->treble= va->treble >> 12; + if(t->treble>= 0x8) + t->treble = (~t->treble & 0xf) + 0x8 ; + + } + + if (va->balance < 32768) + { /* shifted to left, attenuate right */ t->rr = (32768 - va->balance)/1057; t->rf = t->rr; + t->lr = TDA7432_ATTEN_0DB; + t->lf = TDA7432_ATTEN_0DB; } - else { + else if(va->balance > 32769) + { /* shifted to right, attenuate left */ t->lf = (va->balance - 32768)/1057; t->lr = t->lf; + t->rr = TDA7432_ATTEN_0DB; + t->rf = TDA7432_ATTEN_0DB; } - - /* t->tone = 0xff; */ /* Brain hurts - no tone control for now... */ - + else + { + /* centered */ + t->rr = TDA7432_ATTEN_0DB; + t->rf = TDA7432_ATTEN_0DB; + t->lf = TDA7432_ATTEN_0DB; + t->lr = TDA7432_ATTEN_0DB; + } + + tda7432_write(client,TDA7432_TN, (t->bass << 4)| t->treble ); tda7432_write(client,TDA7432_VL, t->volume); - /* tda7432_write(client,TDA7432_TN, t->tone); */ - tda7432_write(client,TDA7432_LF, t->lf); - tda7432_write(client,TDA7432_LR, t->lr); - tda7432_write(client,TDA7432_RF, t->rf); - tda7432_write(client,TDA7432_RR, t->rr); - + + if (va->flags & VIDEO_AUDIO_MUTE) + { + /* Mute & update balance*/ + tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); + tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); + tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); + tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); + } + else + { + tda7432_write(client,TDA7432_LF, t->lf); + tda7432_write(client,TDA7432_LR, t->lr); + tda7432_write(client,TDA7432_RF, t->rf); + tda7432_write(client,TDA7432_RR, t->rr); + } + break; } /* end of VIDEOCSAUDIO case */ @@ -469,11 +517,7 @@ static struct i2c_client client_template = &driver }; -#ifdef MODULE -int init_module(void) -#else int tda7432_init(void) -#endif { if ( (loudness < 0) || (loudness > 15) ) @@ -482,17 +526,17 @@ int tda7432_init(void) return -EINVAL; } - i2c_add_driver(&driver); return 0; } -#ifdef MODULE -void cleanup_module(void) +void tda7432_fini(void) { i2c_del_driver(&driver); } -#endif + +module_init(tda7432_init); +module_exit(tda7432_fini); /* * Local variables: diff --git a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c index 308b3f1dc22d..c26dd99fd848 100644 --- a/drivers/media/video/tuner.c +++ b/drivers/media/video/tuner.c @@ -36,12 +36,16 @@ static int type = -1; /* insmod parameter */ static int addr = 0; static char *pal = "b"; static int this_adap; +static int tv_range[2] = { 44, 958 }; +static int radio_range[2] = { 65, 108 }; #define dprintk if (debug) printk MODULE_PARM(debug,"i"); MODULE_PARM(type,"i"); MODULE_PARM(addr,"i"); +MODULE_PARM(tv_range,"2i"); +MODULE_PARM(radio_range,"2i"); MODULE_PARM(pal,"s"); struct tuner @@ -173,7 +177,20 @@ static struct tunertype tuners[] = { 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623} + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, + 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, + + { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, + 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623} }; #define TUNERS (sizeof(tuners)/sizeof(struct tunertype)) @@ -234,13 +251,13 @@ static void set_tv_freq(struct i2c_client *c, int freq) unsigned char buffer[4]; int rc; - if (freq < 45*16 || freq > 890*16) { + if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { /* FIXME: better do that chip-specific, but right now we don't have that in the config struct and this way is still better than no check at all */ - printk("tuner: TV freq out of range\n"); - return; + printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16,tv_range[0],tv_range[1]); } if (t->type == -1) { @@ -357,8 +374,10 @@ static void set_radio_freq(struct i2c_client *c, int freq) unsigned char buffer[4]; int rc; - if (freq < 76*16 || freq > 108*16) { - printk("tuner: radio freq out of range\n"); + if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { + printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16, + radio_range[0],radio_range[1]); return; } if (t->type == -1) { @@ -410,7 +429,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, client_template.adapter = adap; client_template.addr = addr; - printk("tuner: chip found @ 0x%x\n",addr); + printk("tuner: chip found @ 0x%x\n", addr<<1); if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) return -ENOMEM; diff --git a/drivers/media/video/tuner.h b/drivers/media/video/tuner.h index e85a3741c09d..591ae3e7bc20 100644 --- a/drivers/media/video/tuner.h +++ b/drivers/media/video/tuner.h @@ -47,10 +47,16 @@ #define TUNER_TEMIC_4046FM5 22 /* you must actively select B/G, D/K, I, L, L` ! */ #define TUNER_PHILIPS_PAL_DK 23 #define TUNER_PHILIPS_FQ1216ME 24 /* you must actively select B/G/D/K, I, L, L` */ +#define TUNER_LG_PAL_I_FM 25 +#define TUNER_LG_PAL_I 26 +#define TUNER_LG_NTSC_FM 27 +#define TUNER_LG_PAL_FM 28 +#define TUNER_LG_PAL 29 +#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM 30 /* B/G, I and D/K autodetected */ #define NOTUNER 0 -#define PAL 1 +#define PAL 1 /* PAL_BG */ #define PAL_I 2 #define NTSC 3 #define SECAM 4 @@ -60,6 +66,7 @@ #define TEMIC 2 #define Sony 3 #define Alps 4 +#define LGINNOTEK 5 #define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ #define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index a3856186fc96..5cd813d0bff6 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -98,6 +98,7 @@ struct CHIPDESC { int inputreg; int inputmap[8]; int inputmute; + int inputmask; }; static struct CHIPDESC chiplist[]; @@ -113,7 +114,7 @@ struct CHIPSTATE { /* current settings */ __u16 left,right,treble,bass,mode; - + int prevmode; /* thread */ struct task_struct *thread; struct semaphore *notify; @@ -124,7 +125,7 @@ struct CHIPSTATE { /* ---------------------------------------------------------------------- */ -/* i2c addresses */ +/* i2c addresses */ static unsigned short normal_i2c[] = { I2C_TDA8425 >> 1, @@ -182,6 +183,18 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) return 0; } +static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask) +{ + if (mask != 0) { + if (-1 == subaddr) { + val = (chip->shadow.bytes[1] & ~mask) | (val & mask); + } else { + val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask); + } + } + return chip_write(chip, subaddr, val); +} + static int chip_read(struct CHIPSTATE *chip) { unsigned char buffer; @@ -283,7 +296,6 @@ static int chip_thread(void *data) continue; /* have a look what's going on */ - dprintk("%s: thread checkmode\n", chip->c.name); desc->checkmode(chip); /* schedule next check */ @@ -303,10 +315,16 @@ void generic_checkmode(struct CHIPSTATE *chip) struct CHIPDESC *desc = chiplist + chip->type; int mode = desc->getmode(chip); - if (mode & VIDEO_SOUND_STEREO) - desc->setmode(chip,VIDEO_SOUND_STEREO); - else if (mode & VIDEO_SOUND_LANG1) + if (mode == chip->prevmode) + return; + + dprintk("%s: thread checkmode\n", chip->c.name); + chip->prevmode = mode; + + if (mode & VIDEO_SOUND_LANG1) desc->setmode(chip,VIDEO_SOUND_LANG1); + else if (mode & VIDEO_SOUND_STEREO) + desc->setmode(chip,VIDEO_SOUND_STEREO); else desc->setmode(chip,VIDEO_SOUND_MONO); } @@ -331,6 +349,9 @@ void generic_checkmode(struct CHIPSTATE *chip) #define TDA9840_ST_STEREO 0x40 /* Stereo sound identified */ #define TDA9840_PONRES 0x80 /* Power-on reset detected if = 1 */ +#define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */ +#define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */ + int tda9840_getmode(struct CHIPSTATE *chip) { int val, mode; @@ -528,6 +549,7 @@ void tda985x_setmode(struct CHIPSTATE *chip, int mode) * 1, 0 external stereo * 0, 1 external mono */ +#define TDA9873_INP_MASK 3 #define TDA9873_INTERNAL 0 #define TDA9873_EXT_STEREO 2 #define TDA9873_EXT_MONO 1 @@ -543,6 +565,7 @@ void tda985x_setmode(struct CHIPSTATE *chip, int mode) * 0, 1, 1 Dual BA */ +#define TDA9873_TR_MASK (7 << 2) #define TDA9873_TR_MONO 4 #define TDA9873_TR_STEREO 1 << 4 #define TDA9873_TR_REVERSE (1 << 3) & (1 << 2) @@ -643,10 +666,10 @@ int tda9873_getmode(struct CHIPSTATE *chip) void tda9873_setmode(struct CHIPSTATE *chip, int mode) { - int sw_data = chip->shadow.bytes[TDA9873_SW+1] & 0xe3; + int sw_data = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK; /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ - if (sw_data & 3) { + if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { dprintk("tda9873_setmode(): external input\n"); return; } @@ -667,9 +690,13 @@ void tda9873_setmode(struct CHIPSTATE *chip, int mode) case VIDEO_SOUND_LANG2: sw_data |= TDA9873_TR_DUALB; break; + default: + chip->mode = 0; + return; } - dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); - chip_write(chip,TDA9873_SW,sw_data); + + dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", + mode, sw_data); } int tda9873_checkit(struct CHIPSTATE *chip) @@ -777,7 +804,8 @@ static struct CHIPDESC chiplist[] = { setmode: tda9840_setmode, checkmode: generic_checkmode, - init: { 2, { TDA9840_SW, 0x2a } } + init: { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN + /* ,TDA9840_SW, TDA9840_MONO */} } }, { name: "tda9873h", @@ -795,8 +823,9 @@ static struct CHIPDESC chiplist[] = { init: { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } }, inputreg: TDA9873_SW, - inputmute: 0xc0, - inputmap: {0xa4, 0xa2, 0xa4, 0xa4, 0xc0} + inputmute: TDA9873_MUTE | TDA9873_AUTOMUTE, + inputmap: {0xa0, 0xa2, 0xa0, 0xa0, 0xc0}, + inputmask: TDA9873_INP_MASK | TDA9873_MUTE | TDA9873_AUTOMUTE }, { @@ -932,7 +961,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, chip->c.data = chip; /* find description for the chip */ - dprintk("tvaudio: chip @ addr=0x%x\n",addr<<1); + dprintk("tvaudio: chip @ addr=0x%x\n", addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; @@ -956,7 +985,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, strcpy(chip->c.name,desc->name); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; - + chip->prevmode = -1; /* register */ MOD_INC_USE_COUNT; i2c_attach_client(&chip->c); @@ -1002,6 +1031,7 @@ static int chip_detach(struct i2c_client *client) { struct CHIPSTATE *chip = client->data; + del_timer(&chip->wt); if (NULL != chip->thread) { /* shutdown async thread */ DECLARE_MUTEX_LOCKED(sem); @@ -1034,9 +1064,9 @@ static int chip_command(struct i2c_client *client, case AUDC_SET_INPUT: if (desc->flags & CHIP_HAS_INPUTSEL) { if (*sarg & 0x80) - chip_write(chip,desc->inputreg,desc->inputmute); + chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask); else - chip_write(chip,desc->inputreg,desc->inputmap[*sarg]); + chip_write_masked(chip,desc->inputreg,desc->inputmap[*sarg],desc->inputmask); } break; /* --- v4l ioctls --- */ @@ -1090,9 +1120,11 @@ static int chip_command(struct i2c_client *client, } case VIDIOCSFREQ: { - chip->mode = 0; /* automatic */ + chip->mode = 0; /* automatic */ if (desc->checkmode) { desc->setmode(chip,VIDEO_SOUND_MONO); + if (chip->prevmode != VIDEO_SOUND_MONO) + chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+2*HZ); /* the thread will call checkmode() later */ } diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c index 5d942a499ac3..beef2128909c 100644 --- a/drivers/net/arlan.c +++ b/drivers/net/arlan.c @@ -1435,7 +1435,7 @@ extern inline void arlan_queue_retransmit(struct net_device *dev) ARLAN_DEBUG_EXIT("arlan_queue_retransmit"); }; -extern inline void RetryOrFail(struct net_device *dev) +static inline void RetryOrFail(struct net_device *dev) { struct arlan_private *priv = ((struct arlan_private *) dev->priv); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 8114827e5350..dd3088721ad4 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1775,8 +1775,8 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) Ivec[hwcfg.irq].used = 1; } - if (hwcfg.vector_latch) { - if (!request_region(Vector_Latch, 1, "scc vector latch")) + if (hwcfg.vector_latch && !Vector_Latch) { + if (!request_region(hwcfg.vector_latch, 1, "scc vector latch")) printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch); else Vector_Latch = hwcfg.vector_latch; diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index ff796d26242f..0c29576ea3c5 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -27,7 +27,7 @@ #include <linux/netdevice.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/rtnetlink.h> #include <linux/serial_reg.h> @@ -331,8 +331,8 @@ static int ali_ircc_open(int i, chipio_t *info) self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, GFP_KERNEL|GFP_DMA); if (self->tx_buff.head == NULL) { - kfree(self); kfree(self->rx_buff.head); + kfree(self); return -ENOMEM; } memset(self->tx_buff.head, 0, self->tx_buff.truesize); diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index b54f156dd577..257389d33b36 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -33,7 +33,7 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/rtnetlink.h> #include <linux/usb.h> diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index fb72b89bb091..29d4450e211f 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -118,9 +118,9 @@ static unsigned int addresses[7] __initdata = static int irqs[4] __initdata = {3, 4, 5, 9}; /* From the D-Link ADF file: */ -static unsigned int dlink_addresses[4]= +static unsigned int dlink_addresses[4] __initdata = {0x300, 0x320, 0x340, 0x360}; -static int dlink_irqs[8] = {3, 4, 5, 9, 10, 11, 14, 15}; +static int dlink_irqs[8] __initdata = {3, 4, 5, 9, 10, 11, 14, 15}; struct ne2_adapters_t { unsigned int id; @@ -165,7 +165,7 @@ static void ne_block_output(struct net_device *dev, const int count, * */ -static void dlink_put_eeprom(unsigned char value, unsigned int addr) +static void __init dlink_put_eeprom(unsigned char value, unsigned int addr) { int z; unsigned char v1, v2; @@ -186,7 +186,7 @@ static void dlink_put_eeprom(unsigned char value, unsigned int addr) } } -static void dlink_send_eeprom_bit(unsigned int bit, unsigned int addr) +static void __init dlink_send_eeprom_bit(unsigned int bit, unsigned int addr) { /* shift data bit into correct position */ @@ -200,7 +200,7 @@ static void dlink_send_eeprom_bit(unsigned int bit, unsigned int addr) dlink_put_eeprom(0x09 | bit, addr); } -static void dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigned int addr) +static void __init dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigned int addr) { int z; @@ -216,7 +216,7 @@ static void dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigne } } -static unsigned int dlink_get_eeprom(unsigned int eeaddr, unsigned int addr) +static unsigned int __init dlink_get_eeprom(unsigned int eeaddr, unsigned int addr) { int z; unsigned int value = 0; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index a48bea863038..da91816e379f 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -233,7 +233,7 @@ static void mdio_sync(ioaddr_t ioaddr, int bits); static int mdio_read(ioaddr_t ioaddr, int phy_id, int location); static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value); static u_short read_eeprom(ioaddr_t ioaddr, int index); -static void wait_for_completion(struct net_device *dev, int cmd); +static void tc574_wait_for_completion(struct net_device *dev, int cmd); static void tc574_reset(struct net_device *dev); static void media_check(u_long arg); @@ -515,8 +515,8 @@ static void tc574_config(dev_link_t *link) outw(0x8040, ioaddr + Wn3_Options); mdelay(1); outw(0xc040, ioaddr + Wn3_Options); - wait_for_completion(dev, TxReset); - wait_for_completion(dev, RxReset); + tc574_wait_for_completion(dev, TxReset); + tc574_wait_for_completion(dev, RxReset); mdelay(1); outw(0x8040, ioaddr + Wn3_Options); @@ -656,7 +656,7 @@ static void dump_status(struct net_device *dev) /* Use this for commands that may take time to finish */ -static void wait_for_completion(struct net_device *dev, int cmd) +static void tc574_wait_for_completion(struct net_device *dev, int cmd) { int i = 1500; outw(cmd, dev->base_addr + EL3_CMD); @@ -764,7 +764,7 @@ static void tc574_reset(struct net_device *dev) struct el3_private *lp = (struct el3_private *)dev->priv; int i, ioaddr = dev->base_addr; - wait_for_completion(dev, TotalReset|0x10); + tc574_wait_for_completion(dev, TotalReset|0x10); /* Clear any transactions in progress. */ outw(0, ioaddr + RunnerWrCtrl); @@ -787,8 +787,8 @@ static void tc574_reset(struct net_device *dev) outw(0x8040, ioaddr + Wn3_Options); mdelay(1); outw(0xc040, ioaddr + Wn3_Options); - wait_for_completion(dev, TxReset); - wait_for_completion(dev, RxReset); + tc574_wait_for_completion(dev, TxReset); + tc574_wait_for_completion(dev, RxReset); mdelay(1); outw(0x8040, ioaddr + Wn3_Options); @@ -859,7 +859,7 @@ static void el3_tx_timeout(struct net_device *dev) lp->stats.tx_errors++; dev->trans_start = jiffies; /* Issue TX_RESET and TX_START commands. */ - wait_for_completion(dev, TxReset); + tc574_wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); netif_wake_queue(dev); } @@ -876,7 +876,7 @@ static void pop_tx_status(struct net_device *dev) if (!(tx_status & 0x84)) break; /* reset transmitter on jabber error or underrun */ if (tx_status & 0x30) - wait_for_completion(dev, TxReset); + tc574_wait_for_completion(dev, TxReset); if (tx_status & 0x38) { DEBUG(1, "%s: transmit error: status 0x%02x\n", dev->name, tx_status); @@ -968,12 +968,12 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) " register %04x.\n", dev->name, fifo_diag); if (fifo_diag & 0x0400) { /* Tx overrun */ - wait_for_completion(dev, TxReset); + tc574_wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); } if (fifo_diag & 0x2000) { /* Rx underrun */ - wait_for_completion(dev, RxReset); + tc574_wait_for_completion(dev, RxReset); set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); } @@ -1175,7 +1175,7 @@ static int el3_rx(struct net_device *dev, int worklimit) lp->stats.rx_dropped++; } } - wait_for_completion(dev, RxDiscard); + tc574_wait_for_completion(dev, RxDiscard); } return worklimit; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 1c894b7c518f..a35f51d2dc0b 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -528,7 +528,7 @@ static int tc589_event(event_t event, int priority, /* Use this for commands that may take time to finish */ -static void wait_for_completion(struct net_device *dev, int cmd) +static void tc589_wait_for_completion(struct net_device *dev, int cmd) { int i = 100; outw(cmd, dev->base_addr + EL3_CMD); @@ -686,7 +686,7 @@ static void el3_tx_timeout(struct net_device *dev) lp->stats.tx_errors++; dev->trans_start = jiffies; /* Issue TX_RESET and TX_START commands. */ - wait_for_completion(dev, TxReset); + tc589_wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); netif_wake_queue(dev); } @@ -703,7 +703,7 @@ static void pop_tx_status(struct net_device *dev) if (!(tx_status & 0x84)) break; /* reset transmitter on jabber error or underrun */ if (tx_status & 0x30) - wait_for_completion(dev, TxReset); + tc589_wait_for_completion(dev, TxReset); if (tx_status & 0x38) { DEBUG(1, "%s: transmit error: status 0x%02x\n", dev->name, tx_status); @@ -796,12 +796,12 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) " register %04x.\n", dev->name, fifo_diag); if (fifo_diag & 0x0400) { /* Tx overrun */ - wait_for_completion(dev, TxReset); + tc589_wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); } if (fifo_diag & 0x2000) { /* Rx underrun */ - wait_for_completion(dev, RxReset); + tc589_wait_for_completion(dev, RxReset); set_multicast_list(dev); outw(RxEnable, ioaddr + EL3_CMD); } @@ -1003,7 +1003,7 @@ static int el3_rx(struct net_device *dev) } } /* Pop the top of the Rx FIFO */ - wait_for_completion(dev, RxDiscard); + tc589_wait_for_completion(dev, RxDiscard); } if (worklimit == 0) printk(KERN_NOTICE "%s: too much work in el3_rx!\n", dev->name); diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 84da0179d942..fb4bf2e13aa9 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -49,7 +49,7 @@ #include <linux/init.h> #include <linux/sched.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/module.h> @@ -361,7 +361,7 @@ static void ibmtr_config(dev_link_t *link) mem.CardOffset = mmiobase; mem.Page = 0; CS_CHECK(MapMemPage, link->win, &mem); - ti->mmio = (u_long)ioremap(req.Base, req.Size); + ti->mmio = ioremap(req.Base, req.Size); /* Allocate the SRAM memory window */ req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 78280eae113a..938021dede5b 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -228,7 +228,7 @@ static void __devinit PrtChanID(char *pcid, short stride) printk("\n"); } -static void __devinit HWPrtChanID(__u32 pcid, short stride) +static void __devinit HWPrtChanID(void * pcid, short stride) { short i, j; for (i = 0, j = 0; i < 24; i++, j += stride) @@ -330,7 +330,6 @@ int __devinit ibmtr_probe(struct net_device *dev) for (i = 0; ibmtr_portlist[i]; i++) { int ioaddr = ibmtr_portlist[i]; - if (check_region(ioaddr, IBMTR_IO_EXTENT)) continue; if (!ibmtr_probe1(dev, ioaddr)) return 0; } return -ENODEV; @@ -342,9 +341,9 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) { unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0; - __u32 t_mmio = 0; + void * t_mmio = 0; struct tok_info *ti = 0; - __u32 cd_chanid; + void *cd_chanid; unsigned char *tchanid, ctemp; #ifndef PCMCIA unsigned char t_irq=0; @@ -355,6 +354,8 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) #ifndef MODULE #ifndef PCMCIA dev = init_trdev(dev, 0); + if (!dev) + return -ENOMEM; #endif #endif @@ -377,14 +378,14 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) * Compute the linear base address of the MMIO area * as LINUX doesn't care about segments */ - t_mmio = (u32)ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048); + t_mmio = ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048); if (!t_mmio) { DPRINTK("Cannot remap mmiobase memory area") ; return -ENODEV ; } intr = segment & 0x03; /* low bits is coded interrupt # */ if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n" + DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %p intr: %d\n" , PIOaddr, (int) segment, t_mmio, (int) intr); /* @@ -392,8 +393,9 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) * what we is there to learn of ISA/MCA or not TR card */ #ifdef PCMCIA + iounmap(t_mmio); ti = dev->priv; /*BMS moved up here */ - t_mmio = ti->mmio; /*BMS to get virtual address */ + t_mmio = (void *)ti->mmio; /*BMS to get virtual address */ irq = ti->irq; /*BMS to display the irq! */ #endif cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */ @@ -424,7 +426,12 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e)) cardpresent = TR_ISAPNP; if (cardpresent == NOTOK) { /* "channel_id" did not match, report */ - if (!(ibmtr_debug_trace & TRC_INIT)) return -ENODEV; + if (!(ibmtr_debug_trace & TRC_INIT)) { +#ifndef PCMCIA + iounmap(t_mmio); +#endif + return -ENODEV; + } DPRINTK( "Channel ID string not found for PIOaddr: %4hx\n", PIOaddr); DPRINTK("Expected for ISA: "); @@ -442,7 +449,10 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) waste the memory, just use the existing structure */ #ifndef PCMCIA ti = (struct tok_info *) kmalloc(sizeof(struct tok_info), GFP_KERNEL); - if (ti == NULL) return -ENOMEM; + if (ti == NULL) { + iounmap(t_mmio); + return -ENOMEM; + } memset(ti, 0, sizeof(struct tok_info)); ti->mmio = t_mmio; dev->priv = ti; /* this seems like the logical use of the @@ -459,7 +469,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) ti->turbo=1; t_irq=turbo_irq[i]; } -#endif +#endif /* !PCMCIA */ ti->readlog_pending = 0; init_waitqueue_head(&ti->wait_for_reset); @@ -496,6 +506,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)){ if (!time_after(jiffies, timeout)) continue; DPRINTK( "Hardware timeout during initialization.\n"); + iounmap(t_mmio); kfree(ti); return -ENODEV; } @@ -510,7 +521,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) DPRINTK("irq=%d", irq); printk(", sram_virt=0x%x", ti->sram_virt); if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */ - DPRINTK(", ti->mmio=%08X", ti->mmio); + DPRINTK(", ti->mmio=%p", ti->mmio); printk(", segment=%02X", segment); } printk(".\n"); @@ -609,6 +620,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) default: DPRINTK("Unknown shared ram paging info %01X\n", ti->shared_ram_paging); + iounmap(t_mmio); kfree(ti); return -ENODEV; break; @@ -638,6 +650,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) DPRINTK("Shared RAM for this adapter (%05x) exceeds " "driver limit (%05x), adapter not started.\n", chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE); + iounmap(t_mmio); kfree(ti); return -ENODEV; } else { /* seems cool, record what we have figured out */ @@ -652,16 +665,24 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) { DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n", irq); + iounmap(t_mmio); kfree(ti); return -ENODEV; } /*?? Now, allocate some of the PIO PORTs for this driver.. */ /* record PIOaddr range as busy */ - request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr"); + if (!request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr")) { + DPRINTK("Could not grab PIO range. Halting driver.\n"); + free_irq(dev->irq, dev); + iounmap(t_mmio); + kfree(ti); + return -EBUSY; + } + if (!version_printed++) { printk(version); } -#endif +#endif /* !PCMCIA */ DPRINTK("%s %s found\n", channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 795bb5e7598d..d42545d625a5 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -92,42 +92,58 @@ static void __init quirk_triton(struct pci_dev *dev) * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm * Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for * the info on which Mr Breese based his work. + * + * Updated based on further information from the site and also on + * information provided by VIA */ static void __init quirk_vialatency(struct pci_dev *dev) { - u8 r70; + struct pci_dev *p; u8 rev; - struct pci_dev *vt82c686; - - - /* we want to look for a VT82C686 south bridge, and then apply the via latency - * patch if we find that it's a 686B (by revision) <cpbotha@ieee.org> + u8 busarb; + /* Ok we have a potential problem chipset here. Now see if we have + a buggy southbridge */ + + p=pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); + if(p!=NULL) + { + pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); + /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ + /* Check for buggy part revisions */ + if (rev < 0x40 || rev > 0x42) + return; + } + else + { + p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); + if(p==NULL) /* No problem parts */ + return; + pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); + /* Check for buggy part revisions */ + if (rev < 0x10 || rev > 0x12) + return; + } + + /* + * Ok we have the problem. Now set the PCI master grant to + * occur every master grant. The apparent bug is that under high + * PCI load (quite common in Linux of course) you can get data + * loss when the CPU is held off the bus for 3 bus master requests + * This happens to include the IDE controllers.... + * + * VIA only apply this fix when an SB Live! is present but under + * both Linux and Windows this isnt enough, and we have seen + * corruption without SB Live! but with things like 3 UDMA IDE + * controllers. So we ignore that bit of the VIA recommendation.. */ - vt82c686 = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); - if (vt82c686) - { - pci_read_config_byte(vt82c686, PCI_CLASS_REVISION, &rev); - /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ - if (rev >= 0x40 && rev <= 0x4f) - { - printk(KERN_INFO "Applying VIA PCI latency patch (found VT82C686B).\n"); - /* - * In register 0x70, mask off bit 2 (PCI Master read caching) - * and 1 (Delay Transaction) - */ - pci_read_config_byte(dev, 0x70, &r70); - r70 &= 0xf9; - pci_write_config_byte(dev, 0x70, r70); - /* - * Turn off PCI Latency timeout (set to 0 clocks) - */ - pci_write_config_byte(dev, 0x75, 0x80); - } - else - { - printk(KERN_INFO "Found VT82C686A, not applying VIA latency patch.\n"); - } - } /* if (vt82c686) ... */ + + pci_read_config_byte(dev, 0x76, &busarb); + /* Set bit 4 and bi 5 of byte 76 to 0x01 + "Master priority rotation on every PCI master grant */ + busarb &= ~(1<<5); + busarb |= (1<<4); + pci_write_config_byte(dev, 0x76, busarb); + printk(KERN_INFO "Applying VIA southbridge workaround.\n"); } /* @@ -416,6 +432,8 @@ static struct pci_fixup pci_fixups[] __initdata = { { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, 0x3112 /* Not out yet ? */, quirk_vialatency }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi }, diff --git a/drivers/s390/Config.in b/drivers/s390/Config.in index 1619a064d153..f3b8963cb591 100644 --- a/drivers/s390/Config.in +++ b/drivers/s390/Config.in @@ -14,12 +14,21 @@ comment 'S/390 block device drivers' tristate 'Support for DASD devices' CONFIG_DASD if [ "$CONFIG_DASD" != "n" ]; then - bool ' Support for ECKD Disks' CONFIG_DASD_ECKD - bool ' Support for FBA Disks' CONFIG_DASD_FBA -# bool ' Support for CKD Disks' CONFIG_DASD_CKD - if [ "$CONFIG_ARCH_S390" = "y" ]; then - bool ' Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG + dep_tristate ' Support for ECKD Disks' CONFIG_DASD_ECKD $CONFIG_DASD + if [ "$CONFIG_DASD_ECKD" = "m" ]; then + bool ' Automatic activation of ECKD module' CONFIG_DASD_AUTO_ECKD fi; + dep_tristate ' Support for FBA Disks' CONFIG_DASD_FBA $CONFIG_DASD + if [ "$CONFIG_DASD_FBA" = "m" ]; then + bool ' Automatic activation of FBA module' CONFIG_DASD_AUTO_FBA + fi; +# dep_tristate ' Support for CKD Disks' CONFIG_DASD_CKD $CONFIG_DASD + if [ "$CONFIG_ARCH_S390X" != "y" ]; then + dep_tristate ' Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG $CONFIG_DASD + if [ "$CONFIG_DASD_DIAG" = "m" ]; then + bool ' Automatic activation of DIAG module' CONFIG_DASD_AUTO_DIAG + fi; + fi; fi endmenu diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index 0ddbc31b52d9..bd352622f458 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile @@ -4,15 +4,18 @@ O_TARGET := s390-block.o -list-multi := dasd_mod.o +list-multi := dasd_mod.o dasd_eckd_mod.o dasd_fba_mod.o dasd_diag_mod.o export-objs := dasd.o -dasd_mod-$(CONFIG_DASD_ECKD) += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o -dasd_mod-$(CONFIG_DASD_FBA) += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o -dasd_mod-$(CONFIG_DASD_DIAG) += dasd_diag.o -dasd_mod-objs := dasd.o $(dasd_mod-y) +dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o +dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o +dasd_diag_mod-objs := dasd_diag.o +dasd_mod-objs := dasd.o obj-$(CONFIG_DASD) += dasd_mod.o +obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o +obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o +obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o include $(TOPDIR)/Rules.make @@ -20,3 +23,12 @@ include $(TOPDIR)/Rules.make dasd_mod.o: $(dasd_mod-objs) $(LD) -r -o $@ $(dasd_mod-objs) +dasd_eckd_mod.o: $(dasd_eckd_mod-objs) + $(LD) -r -o $@ $(dasd_eckd_mod-objs) + +dasd_fba_mod.o: $(dasd_fba_mod-objs) + $(LD) -r -o $@ $(dasd_fba_mod-objs) + +dasd_diag_mod.o: $(dasd_diag_mod-objs) + $(LD) -r -o $@ $(dasd_diag_mod-objs) + diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 58e3de6c43fc..94108a201183 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1,14 +1,13 @@ -/* +/* * File...........: linux/drivers/s390/block/dasd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> - * Horst Hummel <Horst.Hummel@de.ibm.com> + * Horst Hummel <Horst.Hummel@de.ibm.com> * Carsten Otte <Cotte@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * * History of changes (starts July 2000) * 11/09/00 complete redesign after code review - * 02/01/01 removed some warnings * 02/01/01 added dynamic registration of ioctls * fixed bug in registration of new majors * fixed handling of request during dasd_end_request @@ -18,13 +17,27 @@ * fixed some race conditions related to modules * added devfs suupport * 03/06/01 refined dynamic attach/detach for leaving devices which are online. - * 06/09/01 refined dynamic modifiaction of devices - * renewed debug feature exploitation + * 03/09/01 refined dynamic modifiaction of devices + * 03/12/01 moved policy in dasd_format to dasdfmt (renamed BIODASDFORMAT) + * 03/19/01 added BIODASDINFO-ioctl + * removed 2.2 compatibility + * 04/27/01 fixed PL030119COT (dasd_disciplines does not work) + * 04/30/01 fixed PL030146HSM (module locking with dynamic ioctls) + * fixed PL030130SBA (handling of invalid ranges) + * 05/02/01 fixed PL030145SBA (killing dasdmt) + * fixed PL030149SBA (status of 'accepted' devices) + * fixed PL030146SBA (BUG in ibm.c after adding device) + * added BIODASDPRRD ioctl interface + * 05/11/01 fixed PL030164MVE (trap in probeonly mode) + * 05/15/01 fixed devfs support for unformatted devices + * 06/26/01 hopefully fixed PL030172SBA,PL030234SBA + * 07/09/01 fixed PL030324MSH (wrong statistics output) + * 07/16/01 merged in new fixes for handling low-mem situations */ -#include <linux/module.h> #include <linux/config.h> #include <linux/version.h> +#include <linux/kmod.h> #include <linux/init.h> #include <linux/blkdev.h> #include <linux/stddef.h> @@ -42,9 +55,9 @@ #include <linux/spinlock.h> #include <linux/devfs_fs_kernel.h> #include <linux/blkpg.h> +#include <linux/wait.h> #include <asm/ccwcache.h> -#include <asm/dasd.h> #include <asm/debug.h> #include <asm/atomic.h> @@ -57,6 +70,9 @@ #include <asm/s390_ext.h> #include <asm/s390dyn.h> #include <asm/idals.h> +#include <asm/dasd.h> + +#include "dasd_int.h" #ifdef CONFIG_DASD_ECKD #include "dasd_eckd.h" @@ -77,20 +93,31 @@ MODULE_DESCRIPTION ("Linux on S/390 DASD device driver," " Copyright 2000 IBM Corporation"); MODULE_SUPPORTED_DEVICE ("dasd"); MODULE_PARM (dasd, "1-" __MODULE_STRING (256) "s"); -EXPORT_SYMBOL (dasd_discipline_enq); -EXPORT_SYMBOL (dasd_discipline_deq); +MODULE_PARM (dasd_disciplines, "1-" __MODULE_STRING (8) "s"); +EXPORT_SYMBOL (dasd_chanq_enq_head); +EXPORT_SYMBOL (dasd_debug_area); +EXPORT_SYMBOL (dasd_chanq_enq); +EXPORT_SYMBOL (dasd_chanq_deq); +EXPORT_SYMBOL (dasd_discipline_add); +EXPORT_SYMBOL (dasd_discipline_del); EXPORT_SYMBOL (dasd_start_IO); +EXPORT_SYMBOL (dasd_term_IO); +EXPORT_SYMBOL (dasd_schedule_bh); EXPORT_SYMBOL (dasd_int_handler); +EXPORT_SYMBOL (dasd_oper_handler); EXPORT_SYMBOL (dasd_alloc_request); EXPORT_SYMBOL (dasd_free_request); -EXPORT_SYMBOL(dasd_ioctl_no_register); -EXPORT_SYMBOL(dasd_ioctl_no_unregister); +EXPORT_SYMBOL (dasd_ioctl_no_register); +EXPORT_SYMBOL (dasd_ioctl_no_unregister); +EXPORT_SYMBOL (dasd_default_erp_action); +EXPORT_SYMBOL (dasd_default_erp_postaction); +EXPORT_SYMBOL (dasd_sleep_on_req); +EXPORT_SYMBOL (dasd_set_normalized_cda); /* SECTION: Constant definitions to be used within this file */ -#define PRINTK_HEADER DASD_NAME": " +#define PRINTK_HEADER DASD_NAME":" -#define DASD_EMERGENCY_REQUESTS 16 #define DASD_MIN_SIZE_FOR_QUEUE 32 #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE #define DASD_CHANQ_MAX_SIZE 6 @@ -98,27 +125,36 @@ EXPORT_SYMBOL(dasd_ioctl_no_unregister); /* SECTION: prototypes for static functions of dasd.c */ static request_fn_proc do_dasd_request; -static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int); +static int dasd_set_device_level (unsigned int, dasd_discipline_t *, int); static request_queue_t *dasd_get_queue (kdev_t kdev); static void cleanup_dasd (void); -int dasd_fillgeo(int kdev,struct hd_geometry *geo); - +static void dasd_plug_device (dasd_device_t * device); +static int dasd_fillgeo (int kdev, struct hd_geometry *geo); +static void dasd_enable_ranges (dasd_range_t *, dasd_discipline_t *, int); +static void dasd_disable_ranges (dasd_range_t *, dasd_discipline_t *, int, int); +static void dasd_enable_single_device ( unsigned long); +static inline int dasd_state_init_to_ready(dasd_device_t*); +static inline void dasd_setup_partitions ( dasd_device_t *); +static inline int dasd_setup_blkdev(dasd_device_t*); +static inline int dasd_disable_blkdev(dasd_device_t*); +static void dasd_flush_chanq ( dasd_device_t * device, int destroy ); +static void dasd_flush_request_queues ( dasd_device_t * device, int destroy ); static struct block_device_operations dasd_device_operations; - +static inline dasd_device_t ** dasd_device_from_devno (int); +static void dasd_process_queues (dasd_device_t * device); /* SECTION: static variables of dasd.c */ static devfs_handle_t dasd_devfs_handle; - -/* SECTION: exported variables of dasd.c */ - -debug_info_t *dasd_debug_area; +static wait_queue_head_t dasd_init_waitq; +static atomic_t dasd_init_pending = ATOMIC_INIT (0); #ifdef CONFIG_DASD_DYNAMIC + /* SECTION: managing dynamic configuration of dasd_driver */ -static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head); +static struct list_head dasd_devreg_head = LIST_HEAD_INIT (dasd_devreg_head); -/* +/* * function: dasd_create_devreg * creates a dasd_devreg_t related to a devno */ @@ -135,7 +171,7 @@ dasd_create_devreg (int devno) return r; } -/* +/* * function: dasd_destroy_devreg * destroys the dasd_devreg_t given as argument */ @@ -153,44 +189,44 @@ dasd_destroy_devreg (dasd_devreg_t * devreg) static int dasd_probeonly = 1; /* is true, when probeonly mode is active */ static int dasd_autodetect = 1; /* is true, when autodetection is active */ -/* dasd_range_t are used for ordering the DASD devices */ -typedef struct dasd_range_t { - unsigned int from; /* first DASD in range */ - unsigned int to; /* last DASD in range */ - char discipline[4]; /* placeholder to force discipline */ - struct dasd_range_t *next; /* next one in linked list */ -} dasd_range_t; - -static dasd_range_t *dasd_range_head = NULL; /* anchor for list of ranges */ +static dasd_range_t dasd_range_head = + { list:LIST_HEAD_INIT (dasd_range_head.list) }; static spinlock_t range_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t dasd_open_count_lock; -/* +/* * function: dasd_create_range - * creates a dasd_range_t according to the arguments + * creates a dasd_range_t according to the arguments * FIXME: no check is performed for reoccurrence of a devno */ static inline dasd_range_t * -dasd_create_range (int from, int to) +dasd_create_range (int from, int to, int features) { dasd_range_t *range = NULL; + int i; + + if ( from > to ) { + printk (KERN_WARNING PRINTK_HEADER "Adding device range %04X-%04X: range invalid, ignoring.\n",from,to); + return NULL; + } + for (i=from;i<=to;i++) { + if (dasd_device_from_devno(i)) { + printk (KERN_WARNING PRINTK_HEADER "device range %04X-%04X: device %04X is already in a range.\n",from,to,i); + } + } range = (dasd_range_t *) kmalloc (sizeof (dasd_range_t), GFP_KERNEL); if (range == NULL) return NULL; memset (range, 0, sizeof (dasd_range_t)); range->from = from; - if (to == 0) { /* single devno ? */ - range->to = from; - } else { - range->to = to; - } + range->to = to; + range->features = features; return range; } -/* +/* * function dasd_destroy_range * destroy a range allocated wit dasd_crate_range - * CAUTION: must not be callen in arunning sysztem, because it destroys + * CAUTION: must not be callen in arunning sysztem, because it destroys * the mapping of DASDs */ static inline void @@ -199,68 +235,50 @@ dasd_destroy_range (dasd_range_t * range) kfree (range); } -/* +/* * function: dasd_append_range - * appends the range given as argument to the list anchored at dasd_range_head. + * appends the range given as argument to the list anchored at dasd_range_head. */ static inline void dasd_append_range (dasd_range_t * range) { - dasd_range_t *temp; long flags; spin_lock_irqsave (&range_lock, flags); - if (dasd_range_head == NULL) { - dasd_range_head = range; - } else { - for (temp = dasd_range_head; - temp && temp->next; - temp = temp->next) ; - temp->next = range; - } + list_add_tail (&range->list, &dasd_range_head.list); spin_unlock_irqrestore (&range_lock, flags); } /* * function dasd_dechain_range * removes a range from the chain of ranges - * CAUTION: must not be called in a running system because it destroys + * CAUTION: must not be called in a running system because it destroys * the mapping of devices */ static inline void dasd_dechain_range (dasd_range_t * range) { - dasd_range_t *temp, *prev = NULL; unsigned long flags; spin_lock_irqsave (&range_lock, flags); - for (temp = dasd_range_head; temp != NULL; temp = temp->next) { - if (temp == range) - break; - prev = temp; - } - if (!temp) - BUG (); - if (prev) { - prev->next = temp->next; - } else { - dasd_range_head = temp->next; - } + list_del (&range->list); spin_unlock_irqrestore (&range_lock, flags); } -/* +/* * function: dasd_add_range * creates a dasd_range_t according to the arguments and * appends it to the list of ranges - * additionally a devreg_t is created and added to the list of devregs + * additionally a devreg_t is created and added to the list of devregs */ -static inline dasd_range_t* -dasd_add_range (int from, int to) +static inline dasd_range_t * +dasd_add_range (int from, int to, int features) { dasd_range_t *range; - range = dasd_create_range (from, to); - if (!range) return NULL; + + range = dasd_create_range (from, to, features); + if (!range) + return NULL; dasd_append_range (range); #ifdef CONFIG_DASD_DYNAMIC @@ -270,14 +288,14 @@ dasd_add_range (int from, int to) for (i = range->from; i <= range->to; i++) { dasd_devreg_t *reg = dasd_create_devreg (i); s390_device_register (®->devreg); - list_add(®->list,&dasd_devreg_head); + list_add (®->list, &dasd_devreg_head); } } #endif /* CONFIG_DASD_DYNAMIC */ return range; } -/* +/* * function: dasd_remove_range * removes a range and the corresponding devregs from all of the chains * CAUTION: must not be called in a running system because it destroys @@ -291,10 +309,10 @@ dasd_remove_range (dasd_range_t * range) { int i; for (i = range->from; i <= range->to; i++) { - struct list_head *l; - dasd_devreg_t *reg = NULL; + struct list_head *l; + dasd_devreg_t *reg = NULL; list_for_each (l, &dasd_devreg_head) { - reg = list_entry(l,dasd_devreg_t,list); + reg = list_entry (l, dasd_devreg_t, list); if (reg->devreg.flag == DEVREG_TYPE_DEVNO && reg->devreg.ci.devno == i && reg->devreg.oper_func == dasd_oper_handler) @@ -323,9 +341,11 @@ dasd_devindex_from_devno (int devno) dasd_range_t *temp; int devindex = 0; unsigned long flags; + struct list_head *l; spin_lock_irqsave (&range_lock, flags); - for (temp = dasd_range_head; temp; temp = temp->next) { + list_for_each (l, &dasd_range_head.list) { + temp = list_entry (l, dasd_range_t, list); if (devno >= temp->from && devno <= temp->to) { spin_unlock_irqrestore (&range_lock, flags); return devindex + devno - temp->from; @@ -336,19 +356,43 @@ dasd_devindex_from_devno (int devno) return -ENODEV; } +/* + * function: dasd_devno_from_devindex + */ +static int +dasd_devno_from_devindex (int devindex) +{ + dasd_range_t *temp; + unsigned long flags; + struct list_head *l; + + spin_lock_irqsave (&range_lock, flags); + list_for_each (l, &dasd_range_head.list) { + temp = list_entry (l, dasd_range_t, list); + if ( devindex < temp->to - temp->from + 1) { + spin_unlock_irqrestore (&range_lock, flags); + return temp->from + devindex; + } + devindex -= temp->to - temp->from + 1; + } + spin_unlock_irqrestore (&range_lock, flags); + return -ENODEV; +} + /* SECTION: parsing the dasd= parameter of the parmline/insmod cmdline */ -/* +/* * char *dasd[] is intended to hold the ranges supplied by the dasd= statement * it is named 'dasd' to directly be filled by insmod with the comma separated * strings when running as a module. * a maximum of 256 ranges can be supplied, as the parmline is limited to * <1024 Byte anyway. */ -char *dasd[256] = {NULL,}; +char *dasd[256]; +char *dasd_disciplines[8]; #ifndef MODULE -/* +/* * function: dasd_split_parm_string * splits the parmline given to the kernel into comma separated strings * which are filled into the 'dasd[]' array, to be parsed later on @@ -358,7 +402,7 @@ dasd_split_parm_string (char *str) { char *tmp = str; int count = 0; - do { + while (tmp != NULL && *tmp != '\0') { char *end; int len; end = strchr (tmp, ','); @@ -370,27 +414,28 @@ dasd_split_parm_string (char *str) end++; } dasd[count] = kmalloc (len * sizeof (char), GFP_ATOMIC); - if (dasd == NULL) { + if (dasd[count] == NULL) { printk (KERN_WARNING PRINTK_HEADER - "can't store dasd= parameter no %d\n", count + 1); + "can't store dasd= parameter no %d\n", + count + 1); break; } memset (dasd[count], 0, len * sizeof (char)); memcpy (dasd[count], tmp, len * sizeof (char)); count++; tmp = end; - } while (tmp != NULL && *tmp != '\0'); + }; } -/* +/* * dasd_parm_string holds a concatenated version of all 'dasd=' parameters - * supplied in the parmline, which is later to be split by + * supplied in the parmline, which is later to be split by * dasd_split_parm_string * FIXME: why first concatenate then split ? */ -static char dasd_parm_string[1024] __initdata = {0,}; +static char dasd_parm_string[1024] __initdata = { 0, }; -/* +/* * function: dasd_setup * is invoked for any single 'dasd=' parameter supplied in the parmline * it merges all the arguments into dasd_parm_string @@ -404,44 +449,90 @@ dasd_setup (char *str, int *ints) } strcat (dasd_parm_string, str); } -/* - * function: dasd_call_setup + +/* + * function: dasd_call_setup * is the 2.4 version of dasd_setup and * is invoked for any single 'dasd=' parameter supplied in the parmline */ int __init dasd_call_setup (char *str) { - int dummy; - dasd_setup(str,&dummy); + int dummy; + dasd_setup (str, &dummy); + return 1; +} + +int __init +dasd_disciplines_setup (char *str) +{ return 1; } __setup ("dasd=", dasd_call_setup); +__setup ("dasd_disciplines=", dasd_disciplines_setup); -#endif /* MODULE */ +#endif /* MODULE */ -/* +/* * function: dasd_strtoul * provides a wrapper to simple_strtoul to strip leading '0x' and * interpret any argument to dasd=[range,...] as hexadecimal */ static inline int -dasd_strtoul (char *str, char **stra) +dasd_strtoul (char *str, char **stra, int* features) { - char *temp = str; - int val; - if (*temp == '0') { - temp++; /* strip leading zero */ - if (*temp == 'x') - temp++; /* strip leading x */ - } - val = simple_strtoul (temp, &temp, 16); /* interpret anything as hex */ - *stra = temp; - return val; + char *temp=str; + char *buffer; + int val,i,start; + + buffer=(char*)kmalloc((strlen(str)+1)*sizeof(char),GFP_ATOMIC); + if (buffer==NULL) { + printk (KERN_WARNING PRINTK_HEADER + "can't parse dasd= parameter %s due to low memory\n", + str); + } + + /* remove leading '0x' */ + if (*temp == '0') { + temp++; /* strip leading zero */ + if (*temp == 'x') + temp++; /* strip leading x */ + } + + /* copy device no to buffer and convert to decimal */ + for (i=0;isxdigit(temp[i]);i++) + buffer[i]=temp[i]; + buffer[i]='\0'; + + val = simple_strtoul (buffer, &buffer, 16); + + /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */ + if (temp[i]=='(') { + + while (temp[i]!='\0' && temp[i]!=')'&&temp[i]!='-') { + start=++i; + + /* move next feature to buffer */ + for (;temp[i]!='\0'&&temp[i]!=':'&&temp[i]!=')'&&temp[i]!='-';i++) + buffer[i-start]=temp[i]; + buffer[i-start]='\0'; + + if (strlen(buffer)) { + if (!strcmp(buffer,"ro")) { /* handle 'ro' feature */ + (*features) |= DASD_FEATURE_READONLY; + break; + } + printk (KERN_WARNING PRINTK_HEADER + "unsupported feature: %s, ignoring setting",buffer); + } + } + } + *stra = temp+i; + return val; } -/* +/* * function: dasd_parse * examines the strings given in the string array str and * creates and adds the ranges to the apropriate lists @@ -451,6 +542,7 @@ dasd_parse (char **str) { char *temp; int from, to; + int features = 0; if (*str) { /* turn off probeonly mode, if any dasd parameter is present */ @@ -472,12 +564,13 @@ dasd_parse (char **str) } else { /* turn off autodetect mode, if any range is present */ dasd_autodetect = 0; - from = dasd_strtoul (temp, &temp); + from = dasd_strtoul (temp, &temp, &features); + to = from; if (*temp == '-') { temp++; - to = dasd_strtoul (temp, &temp); + to = dasd_strtoul (temp, &temp, &features); } - dasd_add_range (from, to); + dasd_add_range (from, to ,features); } str++; } @@ -487,18 +580,16 @@ dasd_parse (char **str) static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED; -static major_info_t dasd_major_info[] = -{ +static major_info_t dasd_major_info[] = { { - list: LIST_HEAD_INIT(dasd_major_info[1].list ) - }, + list:LIST_HEAD_INIT (dasd_major_info[1].list) + }, { - list: LIST_HEAD_INIT(dasd_major_info[0].list ), - gendisk: { - INIT_GENDISK(94,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) - }, - flags : DASD_MAJOR_INFO_IS_STATIC - } + list:LIST_HEAD_INIT (dasd_major_info[0].list), + gendisk:{ + INIT_GENDISK (94, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR) + }, + flags:DASD_MAJOR_INFO_IS_STATIC} }; static major_info_t * @@ -508,17 +599,21 @@ get_new_major_info (void) major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL); if (major_info) { - static major_info_t temp_major_info = - { - gendisk: { - INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR) - } + static major_info_t temp_major_info = { + gendisk:{ + INIT_GENDISK (0, DASD_NAME, DASD_PARTN_BITS, + DASD_PER_MAJOR)} }; memcpy (major_info, &temp_major_info, sizeof (major_info_t)); } return major_info; } +/* + * register major number + * is called with the 'static' major_info during init of the driver or 'NULL' to + * allocate an additional dynamic major. + */ static int dasd_register_major (major_info_t * major_info) { @@ -526,67 +621,86 @@ dasd_register_major (major_info_t * major_info) int major; unsigned long flags; + /* allocate dynamic major */ if (major_info == NULL) { major_info = get_new_major_info (); if (!major_info) { printk (KERN_WARNING PRINTK_HEADER "Cannot get memory to allocate another major number\n"); return -ENOMEM; - } else { - printk (KERN_INFO PRINTK_HEADER - "Created another major number\n"); } } + major = major_info->gendisk.major; - major_info->gendisk.de_arr = (devfs_handle_t*) - kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t), GFP_KERNEL); - memset(major_info->gendisk.de_arr,0,DASD_PER_MAJOR * sizeof(devfs_handle_t)); - major_info->gendisk.flags = (char*) - kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL); - memset(major_info->gendisk.flags,0,DASD_PER_MAJOR * sizeof(char)); + /* init devfs array */ + major_info->gendisk.de_arr = (devfs_handle_t *) + kmalloc (DASD_PER_MAJOR * sizeof (devfs_handle_t), GFP_KERNEL); + memset (major_info->gendisk.de_arr, 0, + DASD_PER_MAJOR * sizeof (devfs_handle_t)); + + /* init flags */ + major_info->gendisk.flags = (char *) + kmalloc (DASD_PER_MAJOR * sizeof (char), GFP_KERNEL); + memset (major_info->gendisk.flags, 0, DASD_PER_MAJOR * sizeof (char)); + + /* register blockdevice */ rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations); if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER - "Cannot register to major no %d, rc = %d\n", major, rc); - return rc; + "Cannot register to major no %d, rc = %d\n", major, rc); + goto out_reg_blkdev; } else { major_info->flags |= DASD_MAJOR_INFO_REGISTERED; } - /* Insert the new major info into dasd_major_info if needed */ - if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC) ){ - spin_lock_irqsave (&dasd_major_lock, flags); - list_add_tail(&major_info->list,&dasd_major_info[0].list); + + /* Insert the new major info into dasd_major_info if needed (dynamic major) */ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { + spin_lock_irqsave (&dasd_major_lock, flags); + list_add_tail (&major_info->list, &dasd_major_info[0].list); spin_unlock_irqrestore (&dasd_major_lock, flags); - } + } + if (major == 0) { major = rc; rc = 0; } - major_info->dasd_device = (dasd_device_t **) kmalloc (DASD_PER_MAJOR * sizeof (dasd_device_t *), - GFP_ATOMIC); + + /* init array of devices */ + major_info->dasd_device = + (dasd_device_t **) kmalloc (DASD_PER_MAJOR * + sizeof (dasd_device_t *), GFP_ATOMIC); if (!major_info->dasd_device) - goto out_devfs; - memset (major_info->dasd_device, 0, DASD_PER_MAJOR * sizeof (dasd_device_t *)); + goto out_devices; + memset (major_info->dasd_device, 0, + DASD_PER_MAJOR * sizeof (dasd_device_t *)); + + /* init blk_size */ blk_size[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!blk_size[major]) - goto out_dasd_device; + goto out_blk_size; memset (blk_size[major], 0, (1 << MINORBITS) * sizeof (int)); + + /* init blksize_size */ blksize_size[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!blksize_size[major]) - goto out_blk_size; + goto out_blksize_size; memset (blksize_size[major], 0, (1 << MINORBITS) * sizeof (int)); + + /* init_hardsect_size */ hardsect_size[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!hardsect_size[major]) - goto out_blksize_size; + goto out_hardsect_size; memset (hardsect_size[major], 0, (1 << MINORBITS) * sizeof (int)); + + /* init max_sectors */ max_sectors[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!max_sectors[major]) - goto out_hardsect_size; + goto out_max_sectors; memset (max_sectors[major], 0, (1 << MINORBITS) * sizeof (int)); /* finally do the gendisk stuff */ @@ -594,29 +708,65 @@ dasd_register_major (major_info_t * major_info) sizeof (struct hd_struct), GFP_ATOMIC); if (!major_info->gendisk.part) - goto out_max_sectors; + goto out_gendisk; memset (major_info->gendisk.part, 0, (1 << MINORBITS) * sizeof (struct hd_struct)); - INIT_BLK_DEV(major,do_dasd_request,dasd_get_queue,NULL); + INIT_BLK_DEV (major, do_dasd_request, dasd_get_queue, NULL); major_info->gendisk.major = major; major_info->gendisk.next = gendisk_head; major_info->gendisk.sizes = blk_size[major]; gendisk_head = &major_info->gendisk; return major; -out_max_sectors: - kfree(max_sectors[major]); -out_hardsect_size: - kfree(hardsect_size[major]); -out_blksize_size: - kfree(blksize_size[major]); -out_blk_size: - kfree(blk_size[major]); -out_dasd_device: - kfree(major_info->dasd_device); -out_devfs: - devfs_unregister_blkdev(major, DASD_NAME); + + /* error handling - free the prior allocated memory */ + out_gendisk: + kfree (max_sectors[major]); + max_sectors[major] = NULL; + + out_max_sectors: + kfree (hardsect_size[major]); + hardsect_size[major] = NULL; + + out_hardsect_size: + kfree (blksize_size[major]); + blksize_size[major] = NULL; + + out_blksize_size: + kfree (blk_size[major]); + blk_size[major] = NULL; + + out_blk_size: + kfree (major_info->dasd_device); + + out_devices: + /* Delete the new major info from dasd_major_info list if needed (dynamic) +*/ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { + spin_lock_irqsave (&dasd_major_lock, flags); + list_del (&major_info->list); + spin_unlock_irqrestore (&dasd_major_lock, flags); + } + + /* unregister blockdevice */ + rc = devfs_unregister_blkdev (major, DASD_NAME); + if (rc < 0) { + printk (KERN_WARNING PRINTK_HEADER + "Unable to unregister from major no %d, rc = %d\n", major, + rc); + } else { + major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED; + } + + out_reg_blkdev: + kfree (major_info->gendisk.flags); + kfree (major_info->gendisk.de_arr); + + /* Delete the new major info from dasd_major_info if needed */ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { + kfree (major_info); + } + return -ENOMEM; } @@ -632,11 +782,7 @@ dasd_unregister_major (major_info_t * major_info) return -EINVAL; } major = major_info->gendisk.major; - INIT_BLK_DEV(major,NULL,NULL,NULL); - blk_size[major] = NULL; - blksize_size[major] = NULL; - hardsect_size[major] = NULL; - max_sectors[major] = NULL; + INIT_BLK_DEV (major, NULL, NULL, NULL); /* do the gendisk stuff */ for (dd = gendisk_head; dd; dd = dd->next) { @@ -652,34 +798,43 @@ dasd_unregister_major (major_info_t * major_info) if (dd == NULL) { return -ENOENT; } - kfree (major_info->gendisk.de_arr); - kfree (major_info->gendisk.flags); kfree (major_info->dasd_device); + kfree (major_info->gendisk.part); + kfree (blk_size[major]); kfree (blksize_size[major]); kfree (hardsect_size[major]); kfree (max_sectors[major]); - kfree (major_info->gendisk.part); + + blk_size[major] = NULL; + blksize_size[major] = NULL; + hardsect_size[major] = NULL; + max_sectors[major] = NULL; rc = devfs_unregister_blkdev (major, DASD_NAME); if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER - "Cannot unregister from major no %d, rc = %d\n", major, rc); + "Cannot unregister from major no %d, rc = %d\n", major, + rc); return rc; } else { major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED; } - /* Delete the new major info from dasd_major_info if needed */ - if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { - spin_lock_irqsave (&dasd_major_lock, flags); - list_del(&major_info->list); + + kfree (major_info->gendisk.flags); + kfree (major_info->gendisk.de_arr); + + /* Delete the new major info from dasd_major_info if needed */ + if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { + spin_lock_irqsave (&dasd_major_lock, flags); + list_del (&major_info->list); spin_unlock_irqrestore (&dasd_major_lock, flags); kfree (major_info); - } + } return rc; } -/* +/* * function: dasd_device_from_kdev * finds the device structure corresponding to the kdev supplied as argument * in the major_info structures and returns it or NULL when not found @@ -692,9 +847,9 @@ dasd_device_from_kdev (kdev_t kdev) unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); - list_for_each(l,&dasd_major_info[0].list) { - major_info = list_entry(l,major_info_t,list); - if ( major_info->gendisk.major == MAJOR(kdev) ) + list_for_each (l, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); + if (major_info->gendisk.major == MAJOR (kdev)) break; } spin_unlock_irqrestore (&dasd_major_lock, flags); @@ -703,10 +858,10 @@ dasd_device_from_kdev (kdev_t kdev) return NULL; } -/* +/* * function: dasd_device_from_devno - * finds the address of the device structure corresponding to the devno - * supplied as argument in the major_info structures and returns + * finds the address of the device structure corresponding to the devno + * supplied as argument in the major_info structures and returns * it or NULL when not found */ static inline dasd_device_t ** @@ -718,8 +873,8 @@ dasd_device_from_devno (int devno) unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); - list_for_each(l,&dasd_major_info[0].list) { - major_info = list_entry(l,major_info_t,list); + list_for_each (l, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); if (devindex < DASD_PER_MAJOR) { spin_unlock_irqrestore (&dasd_major_lock, flags); return &major_info->dasd_device[devindex]; @@ -730,70 +885,105 @@ dasd_device_from_devno (int devno) return NULL; } +/* + * function: dasd_features_from_devno + * finds the device range corresponding to the devno + * supplied as argument in the major_info structures and returns + * the features set for it + */ + +static int +dasd_features_from_devno (int devno) +{ + dasd_range_t *temp; + int devindex = 0; + unsigned long flags; + struct list_head *l; + + spin_lock_irqsave (&range_lock, flags); + list_for_each (l, &dasd_range_head.list) { + temp = list_entry (l, dasd_range_t, list); + if (devno >= temp->from && devno <= temp->to) { + spin_unlock_irqrestore (&range_lock, flags); + return temp->features; + } + devindex += temp->to - temp->from + 1; + } + spin_unlock_irqrestore (&range_lock, flags); + return -ENODEV; +} + + + /* SECTION: managing dasd disciplines */ /* anchor and spinlock for list of disciplines */ -static dasd_discipline_t *dasd_disciplines; +static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head); static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED; -/* - * function dasd_discipline_enq +/* + * function dasd_discipline_enq * chains the discpline given as argument to the head of disiplines * head chaining policy is required to allow module disciplines to * be preferred against those, who are statically linked */ -void +static inline void dasd_discipline_enq (dasd_discipline_t * d) { - spin_lock (&discipline_lock); - d->next = dasd_disciplines; - dasd_disciplines = d; - spin_unlock (&discipline_lock); + list_add(&d->list, &dasd_disc_head); } -/* - * function dasd_discipline_deq +/* + * function dasd_discipline_deq * removes the discipline given as argument from the list of disciplines */ -int +static inline void dasd_discipline_deq (dasd_discipline_t * d) { - int rc = 0; - spin_lock (&discipline_lock); - if (dasd_disciplines == d) { - dasd_disciplines = dasd_disciplines->next; - } else { - dasd_discipline_t *b; - b = dasd_disciplines; - while (b && b->next != d) - b = b->next; - if (b != NULL) { - b->next = b->next->next; - } else { - rc = -ENOENT; - } - } - spin_unlock (&discipline_lock); - return rc; + list_del(&d->list); +} + +void +dasd_discipline_add (dasd_discipline_t * d) +{ + unsigned long flags; + MOD_INC_USE_COUNT; + spin_lock_irqsave (&discipline_lock,flags); + dasd_discipline_enq (d); + spin_unlock_irqrestore (&discipline_lock,flags); + dasd_enable_ranges (&dasd_range_head, d, DASD_STATE_ONLINE); +} + +void dasd_discipline_del (dasd_discipline_t * d) +{ + unsigned long flags; + spin_lock_irqsave (&discipline_lock,flags); + dasd_disable_ranges(&dasd_range_head, d, DASD_STATE_DEL, 1); + dasd_discipline_deq (d); + spin_unlock_irqrestore (&discipline_lock,flags); + MOD_DEC_USE_COUNT; } static inline dasd_discipline_t * -dasd_find_discipline (dasd_device_t * device) +dasd_find_disc (dasd_device_t * device, dasd_discipline_t *d) { - dasd_discipline_t *temp; - for (temp = dasd_disciplines; temp != NULL; temp = temp->next) { - if (temp->id_check) - if (temp->id_check (&device->devinfo)) { - continue; - } - if (temp->check_characteristics) { - if (temp->check_characteristics (device)) { - continue; - } - } - break; - } - return temp; + dasd_discipline_t *t; + struct list_head *l = d ? &d->list : dasd_disc_head.next; + do { + t = list_entry(l,dasd_discipline_t,list); + if ( ( t->id_check == NULL || + t->id_check (&device->devinfo) == 0 ) && + ( t->check_characteristics == NULL || + t->check_characteristics (device) == 0 ) ) + break; + l = l->next; + if ( d || + l == &dasd_disc_head ) { + t = NULL; + break; + } + } while ( 1 ); + return t; } /* SECTION: profiling stuff */ @@ -817,9 +1007,9 @@ static dasd_profile_info_t dasd_global_profile; } /* - * function dasd_profile_add + * function dasd_profile_add * adds the profiling information from the cqr given as argument to the - * global and device specific profiling information + * global and device specific profiling information */ void dasd_profile_add (ccw_req_t * cqr) @@ -844,8 +1034,10 @@ dasd_profile_add (ccw_req_t * cqr) memset (&device->profile, 0, sizeof (dasd_profile_info_t)); }; - dasd_global_profile.dasd_io_reqs++; - device->profile.dasd_io_reqs++; + dasd_global_profile.dasd_io_reqs++; + device->profile.dasd_io_reqs++; + dasd_global_profile.dasd_io_sects+=sectors; + device->profile.dasd_io_sects+=sectors; dasd_profile_add_counter (sectors, dasd_io_secs, device); dasd_profile_add_counter (tottime, dasd_io_times, device); dasd_profile_add_counter (tottimeps, dasd_io_timps, device); @@ -855,14 +1047,130 @@ dasd_profile_add (ccw_req_t * cqr) dasd_profile_add_counter (endtime, dasd_io_time3, device); } + +/* SECTION: All the gendisk stuff */ + + +/* SECTION: Managing wrappers for ccwcache */ + +/* + * function dasd_alloc_request + * tries to return space for a channel program of length cplength with + * additional data of size datasize. + * If the ccwcache cannot fulfill the request it tries the emergeny requests + * before giving up finally + * FIXME: initialization of ccw_req_t should be done by function of ccwcache + */ +ccw_req_t * +dasd_alloc_request (char *magic, int cplength, int datasize, dasd_device_t* device) +{ + ccw_req_t *rv = NULL; + int i; + unsigned long flags; + + if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) { + return rv; + } + if ((((sizeof (ccw_req_t) + 7) & -8) + + cplength * sizeof (ccw1_t) + datasize) > PAGE_SIZE) { + BUG (); + } + if (device->lowmem_cqr==NULL) { + DASD_MESSAGE (KERN_WARNING, device, "Low memory! Using emergency request %p",device->lowmem_ccws); + device->lowmem_cqr=device->lowmem_ccws; + rv = device->lowmem_ccws; + memset (rv, 0, PAGE_SIZE); + strncpy ((char *) (&rv->magic), magic, 4); + ASCEBC ((char *) (&rv->magic), 4); + rv->cplength = cplength; + rv->datasize = datasize; + rv->data = (void *) ((long) rv + PAGE_SIZE - datasize); + rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t)); + } else { + DASD_MESSAGE (KERN_WARNING, device,"Refusing emergency mem for request NULL, already in use at %p.",device->lowmem_ccws); + } + return rv; +} + +/* + * function dasd_free_request + * returns a ccw_req_t to the appropriate cache or emergeny request line + */ +void +dasd_free_request (ccw_req_t * request, dasd_device_t* device) +{ +#ifdef CONFIG_ARCH_S390X + ccw1_t* ccw; + /* clear any idals used for chain */ + ccw=request->cpaddr-1; + do { + ccw++; + if ((ccw->cda < (unsigned long) device->lowmem_idals) || (ccw->cda >= (unsigned long) device->lowmem_idals+PAGE_SIZE)) + clear_normalized_cda (ccw); + else { + if (device->lowmem_idal_ptr != device->lowmem_idals) + DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency idals from request at %p.",request); + device->lowmem_idal_ptr = device->lowmem_idals; + device->lowmem_cqr=NULL; + } + } while ((ccw->flags & CCW_FLAG_CC) || (ccw->flags & CCW_FLAG_DC)); +#endif + if (request != device->lowmem_ccws) { /* compare to lowmem_ccws to protect usage of lowmem_cqr for IDAL only ! */ + ccw_free_request (request); + } else { + DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency request at %p",request); + device->lowmem_cqr=NULL; + } +} + +int +dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device ) +{ +#ifdef CONFIG_ARCH_S390X + int nridaws; + int count = cp->count; + + if (set_normalized_cda (cp, address)!=-ENOMEM) { + return 0; + } + + if ((device->lowmem_cqr!=NULL) && (device->lowmem_cqr!=request)) { + DASD_MESSAGE (KERN_WARNING, device, "Refusing emergency idals for request %p, memory is already in use for request %p",request,device->lowmem_cqr); + return -ENOMEM; + } + device->lowmem_cqr=request; + if (device->lowmem_idal_ptr == device->lowmem_idals) { + DASD_MESSAGE (KERN_WARNING,device, "Low memory! Using emergency IDALs for request %p.\n",request); + } + nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + + (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; + if ( device->lowmem_idal_ptr>=device->lowmem_idals + PAGE_SIZE ) { + /* Ouch! No Idals left for emergency request */ + BUG(); + } + cp->flags |= CCW_FLAG_IDA; + cp->cda = (__u32)(unsigned long)device->lowmem_idal_ptr; + do { + *((long*)device->lowmem_idal_ptr) = address; + address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE); + nridaws --; + device->lowmem_idal_ptr += sizeof(unsigned long); + } while ( nridaws > 0 ); +#else + cp -> cda = address; +#endif + return 0; +} + + /* SECTION: (de)queueing of requests to channel program queues */ -/* - * function dasd_chanq_enq +/* + * function dasd_chanq_enq * appends the cqr given as argument to the queue * has to be called with the queue lock (namely the s390_irq_lock) acquired */ -static inline void +inline void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) { if (q->head != NULL) { @@ -874,35 +1182,33 @@ dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED); } -/* +/* * function dasd_chanq_enq_head * chains the cqr given as argument to the queue head * has to be called with the queue lock (namely the s390_irq_lock) acquired */ -static inline void +inline void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) { cqr->next = q->head; q->head = cqr; if (q->tail == NULL) q->tail = cqr; - check_then_set (&cqr->status, - CQR_STATUS_FILLED, - CQR_STATUS_QUEUED); + check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED); } -/* +/* * function dasd_chanq_deq * dechains the cqr given as argument from the queue * has to be called with the queue lock (namely the s390_irq_lock) acquired */ -int +inline void dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) { ccw_req_t *prev; if (cqr == NULL) - BUG (); + BUG (); if (cqr == q->head) { q->head = cqr->next; @@ -914,138 +1220,82 @@ dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) while (prev && prev->next != cqr) prev = prev->next; if (prev == NULL) - return -ENOENT; + return; prev->next = cqr->next; if (prev->next == NULL) q->tail = prev; } cqr->next = NULL; - return 0; } -/* SECTION: All the gendisk stuff */ +/* SECTION: Managing the device queues etc. */ -/* - * function dasd_partn_detect - * calls the function in genhd, which is appropriate to setup a partitioned disk +/* + * function dasd_start_IO + * attempts to start the IO and returns an appropriate return code */ -static void -dasd_partn_detect (dasd_device_t * dev) +int +dasd_term_IO (ccw_req_t * cqr) { - major_info_t *major_info = dev->major_info; - struct gendisk *dd = &major_info->gendisk; - int minor = MINOR (dev->kdev); - - register_disk (dd, - MKDEV (dd->major, minor), - 1 << DASD_PARTN_BITS, - &dasd_device_operations, - (dev->sizes.blocks << dev->sizes.s2b_shift)); -} - -/* SECTION: Managing wrappers for ccwcache */ - -/* array and spinlock of emergency requests */ -static ccw_req_t *dasd_emergency_req[DASD_EMERGENCY_REQUESTS]; -static spinlock_t dasd_emergency_req_lock = SPIN_LOCK_UNLOCKED; + int rc = 0; + dasd_device_t *device = cqr->device; + int irq; + int retries = 0; -/* - * function dasd_init_emergeny_req - * allocates emergeny requests - */ -static inline void __init -dasd_init_emergency_req (void) -{ - int i; - for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) { - dasd_emergency_req[i] = (ccw_req_t *) get_free_page (GFP_KERNEL); - memset (dasd_emergency_req[i], 0, PAGE_SIZE); + if (!cqr) { + BUG (); } -} - -/* - * function dasd_cleanup_emergeny_req - * tries to free emergeny requests skipping those, which are currently in use - */ -static inline void -dasd_cleanup_emergency_req (void) -{ - int i; - for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) { - if (dasd_emergency_req[i]) - free_page ((long) (dasd_emergency_req[i])); - else - printk (KERN_WARNING PRINTK_HEADER - "losing page for emergency request in use\n"); + irq = device->devinfo.irq; + if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) { + DASD_MESSAGE (KERN_WARNING, device, + " ccw_req_t 0x%08X magic doesn't match" + " discipline 0x%08X\n", + cqr->magic, + *(unsigned int *) device->discipline->name); + return -EINVAL; } -} -/* - * function dasd_alloc_request - * tries to return space for a channel program of length cplength with - * additional data of size datasize. - * If the ccwcache cannot fulfill the request it tries the emergeny requests - * before giving up finally - * FIXME: initialization of ccw_req_t should be done by function of ccwcache - */ -ccw_req_t * -dasd_alloc_request (char *magic, int cplength, int datasize) -{ - ccw_req_t *rv = NULL; - int i; - unsigned long flags; - - if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) { - return rv; - } - if ((((sizeof (ccw_req_t) + 7) & -8) + - cplength*sizeof(ccw1_t) + datasize) > PAGE_SIZE) { - BUG(); + while ( retries < 5 ) { + if ( retries < 2 ) + rc = halt_IO(irq, (long)cqr, + cqr->options | DOIO_WAIT_FOR_INTERRUPT); + else + rc = clear_IO(irq, (long)cqr, + cqr->options | DOIO_WAIT_FOR_INTERRUPT); + switch (rc) { + case 0: + break; + case -ENODEV: + DASD_MESSAGE (KERN_WARNING, device, "%s", + "device gone, retry\n"); + break; + case -EIO: + DASD_MESSAGE (KERN_WARNING, device, "%s", + "I/O error, retry\n"); + break; + case -EBUSY: + DASD_MESSAGE (KERN_WARNING, device, "%s", + "device busy, retry later\n"); + break; + default: + DASD_MESSAGE (KERN_ERR, device, + "line %d unknown RC=%d, please report" + " to linux390@de.ibm.com\n", __LINE__, rc); + BUG (); + break; + } + if (rc == 0) { + check_then_set (&cqr->status, + CQR_STATUS_IN_IO, CQR_STATUS_FAILED); + asm volatile ("STCK %0":"=m" (cqr->stopclk)); + break; + } + retries ++; } - spin_lock_irqsave (&dasd_emergency_req_lock, flags); - for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) { - if (dasd_emergency_req[i] != NULL) { - rv = dasd_emergency_req[i]; - dasd_emergency_req[i] = NULL; - break; - } - } - spin_unlock_irqrestore (&dasd_emergency_req_lock, flags); - if (rv) { - memset (rv, 0, PAGE_SIZE); - rv->cache = (kmem_cache_t *) (dasd_emergency_req + i); - strncpy ((char *) (&rv->magic), magic, 4); - ASCEBC ((char *) (&rv->magic), 4); - rv->cplength = cplength; - rv->datasize = datasize; - rv->data = (void *) ((long) rv + PAGE_SIZE - datasize); - rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t)); - } else { - panic ("No way to fulfill request for I/O request\n"); - } - return rv; + return rc; } -/* - * function dasd_free_request - * returns a ccw_req_t to the appropriate cache or emergeny request line - */ -void -dasd_free_request (ccw_req_t * request) -{ - if ((request->cache >= (kmem_cache_t *) dasd_emergency_req) && - (request->cache < (kmem_cache_t *) (dasd_emergency_req + - DASD_EMERGENCY_REQUESTS))) { - *((ccw_req_t **) (request->cache)) = request; - } else { - ccw_free_request (request); - } -} - -/* SECTION: Managing the device queues etc. */ - - -/* +/* * function dasd_start_IO * attempts to start the IO and returns an appropriate return code */ @@ -1055,7 +1305,7 @@ dasd_start_IO (ccw_req_t * cqr) int rc = 0; dasd_device_t *device = cqr->device; int irq; - unsigned long long now; + unsigned long long now; if (!cqr) { BUG (); @@ -1070,75 +1320,80 @@ dasd_start_IO (ccw_req_t * cqr) return -EINVAL; } - asm volatile ("STCK %0":"=m" (now)); - rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options); - switch (rc) { - case 0: - break; - case -ENODEV: - check_then_set (&cqr->status, - CQR_STATUS_QUEUED, CQR_STATUS_FAILED); - break; - case -EIO: - check_then_set (&cqr->status, - CQR_STATUS_QUEUED, CQR_STATUS_FAILED); - break; - case -EBUSY: - DASD_MESSAGE (KERN_WARNING, device,"%s", - "device busy, retry later\n"); - break; - default: - DASD_MESSAGE (KERN_ERR, device, - "line %d unknown RC=%d, please report" - " to linux390@de.ibm.com\n", - __LINE__, rc); - BUG(); - break; - } + asm volatile ("STCK %0":"=m" (now)); + rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options); + switch (rc) { + case 0: + break; + case -ENODEV: + check_then_set (&cqr->status, + CQR_STATUS_QUEUED, CQR_STATUS_FAILED); + break; + case -EIO: + check_then_set (&cqr->status, + CQR_STATUS_QUEUED, CQR_STATUS_FAILED); + break; + case -EBUSY: + DASD_MESSAGE (KERN_WARNING, device, "%s", + "device busy, retry later\n"); + break; + default: + DASD_MESSAGE (KERN_ERR, device, + "line %d unknown RC=%d, please report" + " to linux390@de.ibm.com\n", __LINE__, rc); + BUG (); + break; + } if (rc == 0) { - check_then_set (&cqr->status, - CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); - cqr->startclk = now; + check_then_set (&cqr->status, + CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); + cqr->startclk = now; } return rc; } -/* - * function sleep_on_req +/* + * function dasd_sleep_on_req * attempts to start the IO and waits for completion * FIXME: replace handmade sleeping by wait_event */ -static int -sleep_on_req (ccw_req_t * req) +int +dasd_sleep_on_req (ccw_req_t * req) { unsigned long flags; int cs; int rc = 0; dasd_device_t *device = (dasd_device_t *) req->device; + if ( signal_pending(current) ) { + return -ERESTARTSYS; + } s390irq_spin_lock_irqsave (device->devinfo.irq, flags); dasd_chanq_enq (&device->queue, req); - /* let the bh start the request to keep them in order */ - dasd_schedule_bh (device); - + /* let the bh start the request to keep them in order */ + dasd_schedule_bh (device); do { s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); - wait_event (device->wait_q, - (((cs=req->status)==CQR_STATUS_DONE)|| - (cs==CQR_STATUS_FAILED))); + wait_event ( device->wait_q, + (((cs = req->status) == CQR_STATUS_DONE) || + (cs == CQR_STATUS_FAILED) || + signal_pending(current))); s390irq_spin_lock_irqsave (device->devinfo.irq, flags); - cs = req->status; + if ( signal_pending(current) ) { + rc = -ERESTARTSYS; + if (req->status == CQR_STATUS_IN_IO ) + device->discipline->term_IO(req); + break; + } else if ( req->status == CQR_STATUS_FAILED) { + rc = -EIO; + break; + } } while (cs != CQR_STATUS_DONE && cs != CQR_STATUS_FAILED); - s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); - if (cs == CQR_STATUS_FAILED) { - rc = -EIO; - } return rc; +} /* end dasd_sleep_on_req */ -} /* end sleep_on_req */ - -/* +/* * function dasd_end_request * posts the buffer_cache about a finalized request * FIXME: for requests splitted to serveral cqrs @@ -1146,7 +1401,8 @@ sleep_on_req (ccw_req_t * req) static inline void dasd_end_request (struct request *req, int uptodate) { - while (end_that_request_first (req, uptodate, DASD_NAME)) {} + while (end_that_request_first (req, uptodate, DASD_NAME)) { + } #ifndef DEVICE_NO_RANDOM add_blkdev_randomness (MAJOR (req->rq_dev)); #endif @@ -1154,7 +1410,7 @@ dasd_end_request (struct request *req, int uptodate) return; } -/* +/* * function dasd_get_queue * returns the queue corresponding to a device behind a kdev */ @@ -1162,10 +1418,10 @@ static request_queue_t * dasd_get_queue (kdev_t kdev) { dasd_device_t *device = dasd_device_from_kdev (kdev); - return &device->request_queue; + return device->request_queue; } -/* +/* * function dasd_check_expire_time * check the request given as argument for expiration * and returns 0 if not yet expired, nonzero else @@ -1177,18 +1433,17 @@ dasd_check_expire_time (ccw_req_t * cqr) int rc = 0; asm volatile ("STCK %0":"=m" (now)); - if ( cqr->expires && - cqr->expires + cqr->startclk < now) { - DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device), + if (cqr->expires && cqr->expires + cqr->startclk < now) { + DASD_MESSAGE (KERN_ERR, ((dasd_device_t *) cqr->device), "IO timeout 0x%08lx%08lx usecs in req %p\n", - (long) (cqr->expires >> 44), - (long) (cqr->expires >> 12), cqr); - cqr->expires <<=1; + (long) (cqr->expires >> 44), + (long) (cqr->expires >> 12), cqr); + cqr->expires <<= 1; } return rc; } -/* +/* * function dasd_finalize_request * implemets the actions to perform, when a request is finally finished * namely in status CQR_STATUS_DONE || CQR_STATUS_FAILED @@ -1196,190 +1451,226 @@ dasd_check_expire_time (ccw_req_t * cqr) static inline void dasd_finalize_request (ccw_req_t * cqr) { - dasd_device_t *device = cqr->device; - + dasd_device_t *device = cqr->device; + asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->req) { - dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE)); - dasd_profile_add (cqr); + dasd_profile_add (cqr); + dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE)); /* free request if nobody is waiting on it */ - dasd_free_request (cqr); + dasd_free_request (cqr, cqr->device); } else { - /* during format we don't have the request structure */ + if ( cqr == device->init_cqr && /* bring late devices online */ + device->level <= DASD_STATE_ONLINE ) { + device->timer.function = dasd_enable_single_device; + device->timer.data = (unsigned long) device; + device->timer.expires = jiffies; + add_timer(&device->timer); + } /* notify sleeping task about finished postprocessing */ wake_up (&device->wait_q); + } return; } -/* +/* * function dasd_process_queues * transfers the requests on the queue given as argument to the chanq * if possible, the request ist started on a fastpath */ static void -dasd_process_queues (dasd_device_t *device) +dasd_process_queues (dasd_device_t * device) { - unsigned long flags; - struct request *req; - request_queue_t * queue = &device->request_queue; + unsigned long flags; + struct request *req; + request_queue_t *queue = device->request_queue; dasd_chanq_t *qp = &device->queue; - int irq = device -> devinfo.irq; - ccw_req_t *final_requests= NULL; - static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE; - int chanq_max_size = DASD_CHANQ_MAX_SIZE; - ccw_req_t * cqr=NULL,*temp; - dasd_erp_postaction_fn_t erp_postaction; - - s390irq_spin_lock_irqsave (irq, flags); - /* First we dechain the requests, processed with completed status */ - while ( qp -> head && - ((qp -> head -> status == CQR_STATUS_DONE) || - (qp -> head -> status == CQR_STATUS_FAILED) || - (qp -> head -> status == CQR_STATUS_ERROR) ) ) { + int irq = device->devinfo.irq; + ccw_req_t *final_requests = NULL; + static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE; + int chanq_max_size = DASD_CHANQ_MAX_SIZE; + ccw_req_t *cqr = NULL, *temp; + dasd_erp_postaction_fn_t erp_postaction; + + + s390irq_spin_lock_irqsave (irq, flags); + + /* First we dechain the requests, processed with completed status */ + while (qp->head && + ((qp->head->status == CQR_STATUS_DONE ) || + (qp->head->status == CQR_STATUS_FAILED) || + (qp->head->status == CQR_STATUS_ERROR ) )) { + dasd_erp_action_fn_t erp_action; - ccw_req_t *erp_cqr = NULL; + ccw_req_t *erp_cqr = NULL; + /* preprocess requests with CQR_STATUS_ERROR */ - if (qp -> head -> status == CQR_STATUS_ERROR) { - if ((qp -> head -> dstat -> flag & DEVSTAT_HALT_FUNCTION) || - (qp->head->retries-- == 0 ) || - (device->discipline->erp_action==NULL) || - ((erp_action=device->discipline->erp_action(qp->head))==NULL)|| - ((erp_cqr = erp_action(qp->head))== NULL)) { - check_then_set (&qp->head->status, + if (qp->head->status == CQR_STATUS_ERROR) { + + qp->head->retries--; + + if (qp->head->dstat->flag & DEVSTAT_HALT_FUNCTION) { + + check_then_set (&qp->head->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - continue; + + } else if ((device->discipline->erp_action == NULL ) || + ((erp_action = device->discipline->erp_action (qp->head)) == NULL) ) { + + erp_cqr = dasd_default_erp_action (qp->head); + + } else { /* call discipline ERP action */ + + erp_cqr = erp_action (qp->head); + } + continue; + + } else if (qp->head->refers) { /* we deal with a finished ERP */ + + if (qp->head->status == CQR_STATUS_DONE) { + + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "ERP successful"); } else { - if (erp_cqr != qp->head){ - dasd_chanq_enq_head (qp, erp_cqr); - } - /* chain of completed requests is now broken */ - continue; + + DASD_MESSAGE (KERN_ERR, device, "%s", + "ERP unsuccessful"); } - } else if ( qp -> head -> refers ) { /* we deal with an ERP */ - char *uptodatestr; - if ( qp -> head -> status == CQR_STATUS_DONE) { - uptodatestr = "ERP successful"; - } else { - uptodatestr = "ERP unsuccessful"; - } - - if (device->discipline->erp_postaction == NULL || - ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL)) { - /* - * maybe we shoud set it to FAILED, - * because we are very paranoid ;) - */ - erp_postaction = default_erp_postaction; + + if ((device->discipline->erp_postaction == NULL )|| + ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL) ) { + + dasd_default_erp_postaction (qp->head); + + } else { /* call ERP postaction of discipline */ + + erp_postaction (qp->head); } - DASD_MESSAGE (KERN_INFO, device, - "%s: postaction [<%p>]\n", - uptodatestr, erp_postaction); - erp_postaction (qp->head); - continue; - } - + + continue; + } + /* dechain request now */ - if ( final_requests == NULL ) - final_requests = qp -> head; - cqr = qp -> head; - qp -> head = qp -> head -> next; + if (final_requests == NULL) + final_requests = qp->head; + + cqr = qp->head; + qp->head = qp->head->next; + if (qp->head == NULL) qp->tail = NULL; - } - if ( cqr ) - cqr -> next = NULL; - /* Now we try to fetch requests from the request queue */ - for (temp = cqr; temp != NULL ;temp=temp-> next ) - if ( temp ->status == CQR_STATUS_QUEUED) - chanq_max_size --; - while ( (! queue->plugged) && - (! list_empty(&queue->queue_head)) && - (req=dasd_next_request(queue)) != NULL) { - /* queue empty or certain critera fulfilled -> transfer */ - if ( qp -> head == NULL || - chanq_max_size > 0 || - (req->nr_sectors >= chanq_min_size)) { - ccw_req_t *cqr; - /* relocate request according to partition table */ - req->sector += device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect; - cqr = device->discipline->build_cp_from_req (device, req); - if (cqr == NULL) { - DASD_MESSAGE (KERN_WARNING, device, - "CCW creation failed on request %p\n", req); - /* revert relocation of request */ - req->sector -= device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect; - break; /* terminate request queue loop */ - - } + + } /* end while over completed requests */ + + if (cqr) + cqr->next = NULL; + /* Now clean the requests with final status */ + while (final_requests) { + temp = final_requests; + final_requests = temp->next; + dasd_finalize_request (temp); + } + /* Now we try to fetch requests from the request queue */ + for (temp = cqr; temp != NULL; temp = temp->next) + if (temp->status == CQR_STATUS_QUEUED) + chanq_max_size--; + while ((atomic_read(&device->plugged) == 0) && + (!queue->plugged) && + (!list_empty (&queue->queue_head)) && + (req = dasd_next_request (queue)) != NULL) { + /* queue empty or certain critera fulfilled -> transfer */ + if (qp->head == NULL || + chanq_max_size > 0 || (req->nr_sectors >= chanq_min_size)) { + ccw_req_t *cqr = NULL; + if (is_read_only(device->kdev) && req->cmd == WRITE) { + DASD_MESSAGE (KERN_WARNING, device, + "rejecting write request %p\n", + req); + dasd_end_request (req, 0); + dasd_dequeue_request (queue,req); + } else { + /* relocate request according to partition table */ + req->sector += + device->major_info->gendisk. + part[MINOR (req->rq_dev)].start_sect; + cqr = device->discipline->build_cp_from_req (device, req); + if (cqr == NULL) { + DASD_MESSAGE (KERN_WARNING, device, + "CCW creation failed on request %p\n", + req); + /* revert relocation of request */ + req->sector -= + device->major_info->gendisk. + part[MINOR (req->rq_dev)].start_sect; + break; /* terminate request queue loop */ + + } #ifdef CONFIG_DYNAMIC_QUEUE_MIN_SIZE - chanq_min_size = (chanq_min_size + req->nr_sectors)>>1; -#endif /* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */ - dasd_dequeue_request(queue,req); - dasd_chanq_enq (qp, cqr); - } else { /* queue not empty OR criteria not met */ - break; /* terminate request queue loop */ - } - } - /* we process the requests with non-final status */ - if ( qp -> head ) { - switch ( qp->head->status ) { - case CQR_STATUS_QUEUED: - /* try to start the first I/O that can be started */ - if ( device->discipline->start_IO (qp->head) != 0) - BUG(); - break; - case CQR_STATUS_IN_IO: - /* Check, if to invoke the missing interrupt handler */ - if ( dasd_check_expire_time (qp->head) ) { - /* to be filled with MIH */ + chanq_min_size = + (chanq_min_size + req->nr_sectors) >> 1; +#endif /* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */ + dasd_dequeue_request (queue, req); + dasd_chanq_enq (qp, cqr); } - break; + } else { /* queue not empty OR criteria not met */ + break; /* terminate request queue loop */ + } + } + /* we process the requests with non-final status */ + if (qp->head) { + switch (qp->head->status) { + case CQR_STATUS_QUEUED: + /* try to start the first I/O that can be started */ + if (device->discipline->start_IO == NULL) + BUG (); + device->discipline->start_IO(qp->head); + break; + case CQR_STATUS_IN_IO: + /* Check, if to invoke the missing interrupt handler */ + if (dasd_check_expire_time (qp->head)) { + /* to be filled with MIH */ + } + break; - case CQR_STATUS_PENDING: - /* just wait */ - break; - default: - BUG(); - } - } - /* Now clean the requests with final status */ - while ( final_requests ) { - cqr = final_requests; - final_requests = cqr-> next; - dasd_finalize_request( cqr ); - } - s390irq_spin_unlock_irqrestore (irq, flags); + case CQR_STATUS_PENDING: + /* just wait */ + break; + default: + BUG (); + } + } + s390irq_spin_unlock_irqrestore (irq, flags); } -/* +/* * function dasd_run_bh * acquires the locks needed and then runs the bh */ static void -dasd_run_bh (dasd_device_t *device) +dasd_run_bh (dasd_device_t * device) { long flags; spin_lock_irqsave (&io_request_lock, flags); - atomic_set(&device->bh_scheduled,0); + atomic_set (&device->bh_scheduled, 0); dasd_process_queues (device); spin_unlock_irqrestore (&io_request_lock, flags); } -/* +/* * function dasd_schedule_bh * schedules the request_fn to run with next run_bh cycle */ void -dasd_schedule_bh (dasd_device_t *device) +dasd_schedule_bh (dasd_device_t * device) { /* Protect against rescheduling, when already running */ - if (atomic_compare_and_swap(0,1,&device->bh_scheduled)) { - return; - } + if (atomic_compare_and_swap (0, 1, &device->bh_scheduled)) { + return; + } - INIT_LIST_HEAD(&device->bh_tq.list); + INIT_LIST_HEAD (&device->bh_tq.list); device->bh_tq.sync = 0; device->bh_tq.routine = (void *) (void *) dasd_run_bh; device->bh_tq.data = device; @@ -1389,46 +1680,24 @@ dasd_schedule_bh (dasd_device_t *device) return; } -/* +/* * function do_dasd_request - * is called from ll_rw_blk.c and provides the caller of + * is called from ll_rw_blk.c and provides the caller of * dasd_process_queues */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static void do_dasd_request (request_queue_t * queue) { - dasd_device_t *device = (dasd_device_t *) - ((long)queue-(long)offsetof (dasd_device_t, request_queue)); + dasd_device_t *device = (dasd_device_t *)queue->queuedata; dasd_process_queues (device); } -#else -static void -do_dasd_request (void) -{ - major_info_t *major_info; - dasd_device_t *device; - int i; - - for (major_info = dasd_major_info; - major_info != NULL; - major_info = major_info->next) { - for (i = 0; i < DASD_PER_MAJOR; i++) { - device = major_info->dasd_device[i]; - if (!device) - continue; /* remove indentation level */ - dasd_process_queues (device); - } - } -} -#endif /* LINUX_IS_24 */ /* - * DASD_HANDLE_STATE_CHANGE_PENDING + * DASD_HANDLE_STATE_CHANGE_PENDING * * DESCRIPTION * Handles the state change pending interrupt. - * Search for the device related request queue and check if the first + * Search for the device related request queue and check if the first * cqr in queue in in status 'CQR_STATUE_PENDING'. * If so the status is set to 'CQR_STATUS_QUEUED' to reactivate * the device. @@ -1436,43 +1705,42 @@ do_dasd_request (void) * PARAMETER * stat device status of state change pending interrupt. */ -void -dasd_handle_state_change_pending (devstat_t *stat) +void +dasd_handle_state_change_pending (devstat_t * stat) { - dasd_device_t **device_addr; - ccw_req_t *cqr; + dasd_device_t **device_addr; + ccw_req_t *cqr; device_addr = dasd_device_from_devno (stat->devno); - if (device_addr == NULL) { - printk (KERN_INFO PRINTK_HEADER - "unable to find device for state change pending " - "interrupt: devno%04X\n", - stat->devno); - } else { - /* re-activate first request in queue */ - cqr = (*device_addr)->queue.head; + if (device_addr == NULL) { - if (cqr->status == CQR_STATUS_PENDING) { + printk (KERN_DEBUG PRINTK_HEADER + "unable to find device for state change pending " + "interrupt: devno%04X\n", stat->devno); + } else { + /* re-activate first request in queue */ + cqr = (*device_addr)->queue.head; - DASD_MESSAGE (KERN_INFO, (*device_addr), - "%s", - "device request queue restarted by " - "state change pending interrupt\n"); + if (cqr->status == CQR_STATUS_PENDING) { - del_timer(&(*device_addr)->timer); + DASD_MESSAGE (KERN_DEBUG, (*device_addr), + "%s", + "device request queue restarted by " + "state change pending interrupt\n"); - check_then_set(&cqr->status, - CQR_STATUS_PENDING, - CQR_STATUS_QUEUED); + del_timer (&(*device_addr)->timer); - dasd_schedule_bh(*device_addr); + check_then_set (&cqr->status, + CQR_STATUS_PENDING, CQR_STATUS_QUEUED); - } - } -} /* end dasd_handle_state_change_pending */ + dasd_schedule_bh (*device_addr); -/* + } + } +} /* end dasd_handle_state_change_pending */ + +/* * function dasd_int_handler * is the DASD driver's default interrupt handler for SSCH-IO */ @@ -1480,16 +1748,14 @@ void dasd_int_handler (int irq, void *ds, struct pt_regs *regs) { int ip; - int devno; ccw_req_t *cqr; dasd_device_t *device; unsigned long long now; -#ifdef ERP_DEBUG - static int counter = 0; -#endif dasd_era_t era = dasd_era_none; /* default is everything is okay */ devstat_t *stat = (devstat_t *)ds; + DASD_DRIVER_DEBUG_EVENT (4, dasd_int_handler, + "Interrupt: IRQ 0x%x",irq); asm volatile ("STCK %0":"=m" (now)); if (stat == NULL) { BUG(); @@ -1499,145 +1765,148 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) if (stat->dstat & (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP )) { - + DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler, + "State change Interrupt: %04X", + stat->devno); dasd_handle_state_change_pending (stat); //return; /* TBD */ } ip = stat->intparm; if (!ip) { /* no intparm: unsolicited interrupt */ - printk (KERN_INFO PRINTK_HEADER + DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler, + "Unsolicited Interrupt: %04X", + stat->devno); + printk (KERN_DEBUG PRINTK_HEADER "unsolicited interrupt: irq0x%x devno%04X\n", irq,stat->devno); return; } if (ip & 0x80000001) { - printk (KERN_INFO PRINTK_HEADER + DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler, + "spurious Interrupt: %04X", + stat->devno); + printk (KERN_DEBUG PRINTK_HEADER "spurious interrupt: irq0x%x devno%04X, parm %08x\n", irq,stat->devno,ip); return; } cqr = (ccw_req_t *)(long)ip; device = (dasd_device_t *) cqr->device; - if (device == NULL || device != ds-offsetof(dasd_device_t,dev_status)) { + if (device == NULL || + device != ds-offsetof(dasd_device_t,dev_status)) { BUG(); } - devno = device->devinfo.devno; if (device->devinfo.irq != irq) { BUG(); } if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) { BUG(); } -#ifdef ERP_DEBUG - if ((++counter % 937 >= 0) && - ( counter % 937 <= 10) && - ( counter < 5000 ) && - ( counter > 2000 ) ){ - static int fake_count = 0; - printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); - printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count); - printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); +#ifdef ERP_FAKE + { + static int counter = 0; + static int fake_count = 0; + + if ((++counter % 937 >= 0) && + ( counter % 937 <= 10) && + ( counter < 5000) && + ( counter > 2000) ) { + + char *sense = stat->ii.sense.data; + + printk (KERN_INFO PRINTK_HEADER + "***********************************************\n"); + printk (KERN_INFO PRINTK_HEADER + "Faking I/O error to recover from; cntr=%i / %02X\n", + counter, ++fake_count); + printk (KERN_INFO PRINTK_HEADER + "***********************************************\n"); + era = dasd_era_recover; - stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; + stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; stat->dstat |= 0x02; -// sense 32 - { - char *sense = stat->ii.sense.data; - sense [25] = 0x1D; - sense [27] = 0x00; - //sense [25] = (fake_count % 256); //0x1B; - //sense [27] = 0x00; - } -// sense 24 -// { -// char *sense = stat->ii.sense.data; -// sense [0] = (counter % 0xFF); //0x1B; -// sense [1] = ((counter * 7) % 0xFF); //0x1B; -// sense [2] = (fake_count % 0xFF); //0x1B; -// sense [27] = 0x80; -// } + memset(sense,0,32); -/* - memset(stat->ii.sense.data,0,32); - stat->ii.sense.data[2] = 0x06; - stat->ii.sense.data[4] = 0x04; - stat->ii.sense.data[5] = 0x60; - stat->ii.sense.data[6] = 0x41; - stat->ii.sense.data[8] = 0xff; - stat->ii.sense.data[9] = 0xff; - stat->ii.sense.data[15] = 0x05; - stat->ii.sense.data[16] = 0x21; - stat->ii.sense.data[18] = 0x60; - stat->ii.sense.data[19] = 0x3b; - stat->ii.sense.data[20] = 0x24; - stat->ii.sense.data[21] = 0x61; - stat->ii.sense.data[22] = 0x65; - stat->ii.sense.data[23] = 0x03; - stat->ii.sense.data[24] = 0x04; - stat->ii.sense.data[25] = 0x10; - stat->ii.sense.data[26] = 0x4e; -*/ - } -#endif - /* first of all lets try to find out the appropriate era_action */ - if ( stat->flag & DEVSTAT_FLAG_SENSE_AVAIL || - stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END) ) { - /* anything abnormal ? */ - if ( device->discipline->examine_error == NULL || - stat->flag & DEVSTAT_HALT_FUNCTION ) { - era = dasd_era_fatal; - } else { - era = device->discipline->examine_error (cqr, stat); + /* 32 byte sense (byte 27 bit 1 = 0)*/ + sense[25] = 0x1D; +// sense [25] = (fake_count % 256); //0x1B; + + /* 24 byte sense (byte 27 bit 1 = 1)*/ +// sense [0] = (counter % 0xFF); //0x1B; +// sense [1] = ((counter * 7) % 0xFF); //0x1B; +// sense [2] = (fake_count % 0xFF); //0x1B; +// sense [27] = 0x80; } } +#endif /* ERP_FAKE */ + /* first of all lets try to find out the appropriate era_action */ + DASD_DEVICE_DEBUG_EVENT (4, device," Int: CS/DS 0x%04X", + ((stat->cstat<<8)|stat->dstat)); + /* first of all lets try to find out the appropriate era_action */ + if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL || + stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { + /* anything abnormal ? */ + if (device->discipline->examine_error == NULL || + stat->flag & DEVSTAT_HALT_FUNCTION) { + era = dasd_era_fatal; + } else { + era = device->discipline->examine_error (cqr, stat); + } + DASD_DRIVER_DEBUG_EVENT (1, dasd_int_handler," era_code %d", + era); + } if ( era == dasd_era_none ) { - if (device->level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING) - device->level = DASD_DEVICE_LEVEL_ANALYSIS_PREPARED; check_then_set(&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE); cqr->stopclk=now; - cqr=cqr->next; /* start the next queued request if possible -> fast_io */ - if (cqr->status == CQR_STATUS_QUEUED) { - if (device->discipline->start_IO (cqr) != 0) { + if (cqr->next && + cqr->next->status == CQR_STATUS_QUEUED) { + if (device->discipline->start_IO (cqr->next) != 0) { printk (KERN_WARNING PRINTK_HEADER "Interrupt fastpath failed!\n"); } } } else { /* error */ - if (cqr->dstat == NULL) - cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC); - if (cqr->dstat) { - memcpy (cqr->dstat, stat, sizeof (devstat_t)); - } else { - PRINT_ERR ("no memory for dstat...ignoring\n"); - } - /* dump sense data */ - if (device->discipline && - device->discipline->dump_sense) { - char *errmsg = device->discipline->dump_sense (device, cqr); - if (errmsg != NULL) { - printk ("Sense data:\n%s", errmsg); - free_page ((unsigned long) errmsg); - } else { - printk (KERN_WARNING PRINTK_HEADER - "No memory to dump error message\n"); - } - } - switch(era) { - case dasd_era_fatal: - check_then_set (&cqr->status,CQR_STATUS_IN_IO, - CQR_STATUS_FAILED); - break; - case dasd_era_recover: - check_then_set (&cqr->status,CQR_STATUS_IN_IO, - CQR_STATUS_ERROR); - break; - default: - BUG(); - } - } + if (cqr->dstat == NULL) + cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC); + if (cqr->dstat) { + memcpy (cqr->dstat, stat, sizeof (devstat_t)); + } else { + PRINT_ERR ("no memory for dstat...ignoring\n"); + } + +#ifdef ERP_DEBUG + /* dump sense data */ + if (device->discipline && + device->discipline->dump_sense ) { + + device->discipline->dump_sense (device, + cqr); + } +#endif + + switch (era) { + case dasd_era_fatal: + check_then_set (&cqr->status, CQR_STATUS_IN_IO, + CQR_STATUS_FAILED); + break; + case dasd_era_recover: + check_then_set (&cqr->status, CQR_STATUS_IN_IO, + CQR_STATUS_ERROR); + break; + default: + BUG (); + } + } + if ( cqr == device->init_cqr && + ( cqr->status == CQR_STATUS_DONE || + cqr->status == CQR_STATUS_FAILED )){ + dasd_state_init_to_ready(device); + if ( atomic_read(&dasd_init_pending) == 0) + wake_up (&dasd_init_waitq); + } dasd_schedule_bh (device); } @@ -1657,26 +1926,39 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) * erp CQR performing the ERP */ ccw_req_t * -default_erp_action (ccw_req_t * cqr) +dasd_default_erp_action (ccw_req_t * cqr) { - ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); - printk (KERN_WARNING PRINTK_HEADER - "Default ERP called... \n"); + dasd_device_t *device = cqr->device; + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device); + + printk (KERN_DEBUG PRINTK_HEADER "Default ERP called... \n"); + + if (!erp) { - if (erp == NULL) - return NULL; + DASD_MESSAGE (KERN_ERR, device, "%s", + "Unable to allocate ERP request"); + + check_then_set (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return cqr; + } erp->cpaddr->cmd_code = CCW_CMD_TIC; - erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr; - erp->function = default_erp_action; - erp->refers = cqr; + erp->cpaddr->cda = (__u32) (void *) cqr->cpaddr; + erp->function = dasd_default_erp_action; + erp->refers = (unsigned int) (unsigned long) cqr; erp->device = cqr->device; erp->magic = cqr->magic; erp->retries = 16; erp->status = CQR_STATUS_FILLED; + dasd_chanq_enq_head (&device->queue, + erp); + return erp; } @@ -1687,6 +1969,8 @@ default_erp_action (ccw_req_t * cqr) * Frees all ERPs of the current ERP Chain and set the status * of the original CQR either to CQR_STATUS_DONE if ERP was successful * or to CQR_STATUS_FAILED if ERP was NOT successful. + * NOTE: This function is only called if no discipline postaction + * is available * * PARAMETER * erp current erp_head @@ -1695,96 +1979,63 @@ default_erp_action (ccw_req_t * cqr) * cqr pointer to the original CQR */ ccw_req_t * -default_erp_postaction (ccw_req_t * erp) +dasd_default_erp_postaction (ccw_req_t *erp) { - ccw_req_t *cqr = NULL, *free_erp = NULL; - dasd_device_t *device = NULL; - int success; - - device = (dasd_device_t *) (erp->device); + + ccw_req_t *cqr = NULL, + *free_erp = NULL; + dasd_device_t *device = erp->device; + int success; + + if (erp->refers == NULL || + erp->function == NULL ) { + + BUG (); + } if (erp->status == CQR_STATUS_DONE) success = 1; else success = 0; -#ifdef ERP_DEBUG - - /* print current erp_chain */ - printk (KERN_WARNING PRINTK_HEADER - "default ERP postaction called for erp chain:\n"); - { - ccw_req_t *temp_erp = NULL; - for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){ - printk(KERN_WARNING PRINTK_HEADER - " erp %p refers to %p with erp function %p\n", - temp_erp, - temp_erp->refers, - temp_erp->function ); - } - } - -#endif /* ERP_DEBUG*/ - - if (erp->refers == NULL || erp->function == NULL) { - BUG(); - } - if (erp->function != default_erp_action) { - printk (KERN_WARNING PRINTK_HEADER - "default ERP postaction called ERP action [<%p>]\n", - erp->function); - } /* free all ERPs - but NOT the original cqr */ - while (erp->refers != NULL) { - free_erp = erp; - erp = erp->refers; + + free_erp = erp; + erp = erp->refers; + /* remove the request from the device queue */ - dasd_chanq_deq (&device->queue, free_erp); + dasd_chanq_deq (&device->queue, + free_erp); + /* free the finished erp request */ - dasd_free_request (free_erp); + dasd_free_request (free_erp, free_erp->device); } - + /* save ptr to original cqr */ cqr = erp; -#ifdef ERP_DEBUG - printk (KERN_INFO PRINTK_HEADER - "default_erp_postaction - left original request = %p \n",cqr); -#endif /* ERP_DEBUG */ - /* set corresponding status to original cqr */ if (success) { + check_then_set (&cqr->status, - CQR_STATUS_ERROR, - CQR_STATUS_DONE); + CQR_STATUS_ERROR, + CQR_STATUS_DONE); } else { + check_then_set (&cqr->status, - CQR_STATUS_ERROR, + CQR_STATUS_ERROR, CQR_STATUS_FAILED); } -#ifdef ERP_DEBUG - /* print current erp_chain */ - printk (KERN_WARNING PRINTK_HEADER - "default ERP postaction finished with remaining chain:\n"); - { - ccw_req_t *temp_erp = NULL; - for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { - printk (KERN_WARNING PRINTK_HEADER - " erp %p refers to %p \n", - temp_erp, temp_erp->refers); - } - } -#endif /* ERP_DEBUG */ - return cqr; -} /* end default_erp_postaction */ + +} /* end default_erp_postaction */ /* SECTION: The helpers of the struct file_operations */ -/* - * function dasd_format +/* + * function dasd_format * performs formatting of _device_ according to _fdata_ * Note: The discipline's format_function is assumed to deliver formatting * commands to format a single unit of the device. In terms of the ECKD @@ -1795,196 +2046,114 @@ static int dasd_format (dasd_device_t * device, format_data_t * fdata) { int rc = 0; - int format_done = 0; - ccw_req_t *req = NULL; - format_data_t temp = - { - fdata->start_unit, - fdata->stop_unit, - fdata->blksize, - fdata->intensity - }; - - spin_lock (&dasd_open_count_lock); - if (device->open_count != 1) { - DASD_MESSAGE (KERN_INFO, device, - "device is already open %d times", - device->open_count); - spin_unlock(&dasd_open_count_lock); - return -EINVAL; - } - if (!device->discipline->format_device) { - spin_unlock(&dasd_open_count_lock); - return -EINVAL; + int openct = atomic_read (&device->open_count); + + if (openct > 1) { + DASD_MESSAGE (KERN_WARNING, device, "%s", + "dasd_format: device is open! expect errors."); } - device->open_count = -1; - spin_unlock (&dasd_open_count_lock); - /* downgrade state of the device */ - dasd_set_device_level (device->devinfo.irq, - DASD_DEVICE_LEVEL_RECOGNIZED, - device->discipline, - 0); - DASD_MESSAGE (KERN_INFO, device, - "Starting format from %d to %d (%d B blocks flags %d", - fdata->start_unit, - fdata->stop_unit, - fdata->blksize, - fdata->intensity); - /* Invalidate first track */ - if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT && - fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && - fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { - format_data_t temp2 = - {0, 0, fdata->blksize, 0x04}; - DASD_MESSAGE (KERN_INFO, device, - "%s", - "Invalidating first track..."); - req = device->discipline->format_device (device, &temp2); - if (req) { - rc = sleep_on_req (req); - dasd_free_request (req); /* request is no longer used */ - } else { - rc = -EINVAL; + DASD_MESSAGE (KERN_INFO, device, + "formatting units %d to %d (%d B blocks) flags %d", + fdata->start_unit, fdata->stop_unit, + fdata->blksize, fdata->intensity); + while ((!rc) && (fdata->start_unit <= fdata->stop_unit)) { + ccw_req_t *req; + dasd_format_fn_t ffn = device->discipline->format_device; + ffn = device->discipline->format_device; + if (ffn == NULL) + break; + req = ffn (device, fdata); + if (req == NULL) { + rc = -ENOMEM; + break; } - if (rc) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Can't invalidate Track 0\n"); - } else { - DASD_MESSAGE (KERN_INFO, device, - "%s", - "...Invalidation complete"); - } - temp.start_unit++; - } - /* format remainnig tracks of device */ - while (!rc && - ((req = device->discipline->format_device (device, &temp)) != NULL) ) { - format_done=1; - if ((rc = sleep_on_req (req)) != 0) { - - + if ((rc = dasd_sleep_on_req (req)) != 0) { DASD_MESSAGE (KERN_WARNING, device, - " Formatting failed with rc = %d\n", - rc); + " Formatting of unit %d failed with rc = %d\n", + fdata->start_unit, rc); break; - } - - dasd_free_request (req); /* request is no longer used */ - temp.start_unit++; - } - - if (!rc && - req == NULL ) { - if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT && - fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && - fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) { - format_data_t temp2 = - {0, 0, fdata->blksize, fdata->intensity}; - DASD_MESSAGE (KERN_INFO, device, - "%s", - "Revalidating first track..."); - req = device->discipline->format_device (device, &temp2); - if (req) { - rc = sleep_on_req (req); - dasd_free_request (req); /* request is no longer used */ - } else { - rc = -EINVAL; - } - if (rc) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Can't revalidate Track 0\n"); - } else { - DASD_MESSAGE (KERN_INFO, device, - "%s", - "...Revalidation complete"); - } - } - } /* end if no more requests */ - - /* check if at least one format cp was build in discipline */ - if (!format_done) { - rc = -EINVAL; - } - - if (rc) - DASD_MESSAGE (KERN_WARNING, device, - "%s", " Formatting finished unsuccessfully"); - else - DASD_MESSAGE (KERN_INFO, device, - "%s", " Formatting finished successfully"); - - /* - * re-analyse device - */ - dasd_set_device_level (device->devinfo.irq, - DASD_DEVICE_LEVEL_ONLINE, - device->discipline, - 0); - udelay (1500000); - - dasd_set_device_level (device->devinfo.irq, - DASD_DEVICE_LEVEL_ONLINE, - device->discipline, - 0); - - spin_lock (&dasd_open_count_lock); - device->open_count=1; - spin_unlock (&dasd_open_count_lock); + } + dasd_free_request (req, device); /* request is no longer used */ + if ( signal_pending(current) ) + break; + fdata->start_unit++; + } return rc; } /* end dasd_format */ -static struct list_head dasd_ioctls = LIST_HEAD_INIT(dasd_ioctls); +static struct list_head dasd_ioctls = LIST_HEAD_INIT (dasd_ioctls); static dasd_ioctl_list_t * -dasd_find_ioctl( int no ) +dasd_find_ioctl (int no) { struct list_head *curr; - list_for_each(curr,&dasd_ioctls){ - if (list_entry(curr,dasd_ioctl_list_t,list)->no == no ){ - return list_entry(curr,dasd_ioctl_list_t,list); + list_for_each (curr, &dasd_ioctls) { + if (list_entry (curr, dasd_ioctl_list_t, list)->no == no) { + return list_entry (curr, dasd_ioctl_list_t, list); } } return NULL; } int -dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler ) +dasd_ioctl_no_register (struct module *owner, int no, dasd_ioctl_fn_t handler) { dasd_ioctl_list_t *new; - if (dasd_find_ioctl(no)) + if (dasd_find_ioctl (no)) return -EBUSY; - new = kmalloc(sizeof(dasd_ioctl_list_t),GFP_KERNEL); - if ( new == NULL ) + new = kmalloc (sizeof (dasd_ioctl_list_t), GFP_KERNEL); + if (new == NULL) return -ENOMEM; - new -> no = no; - new -> handler = handler; - list_add(&new->list,&dasd_ioctls); -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif + new->owner = owner; + new->no = no; + new->handler = handler; + list_add (&new->list, &dasd_ioctls); + MOD_INC_USE_COUNT; return 0; } int -dasd_ioctl_no_unregister ( int no, dasd_ioctl_fn_t handler ) -{ - dasd_ioctl_list_t *old = dasd_find_ioctl(no); - if ( old == NULL ) +dasd_ioctl_no_unregister (struct module *owner, int no, dasd_ioctl_fn_t handler) +{ + dasd_ioctl_list_t *old = dasd_find_ioctl (no); + if (old == NULL) return -ENOENT; - if ( old->no != no || - old->handler != handler ) + if (old->no != no || old->handler != handler || owner != old->owner ) return -EINVAL; - list_del(&old->list); - kfree(old); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif + list_del (&old->list); + kfree (old); + MOD_DEC_USE_COUNT; return 0; } static int +dasd_revalidate (dasd_device_t * device) +{ + int rc = 0; + int i; + kdev_t kdev = device->kdev; + int openct = atomic_read (&device->open_count); + int start = MINOR (kdev); + if (openct != 1) { + DASD_MESSAGE (KERN_WARNING, device, "%s", + "BLKRRPART: device is open! expect errors."); + } + for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) { + int major = device->major_info->gendisk.major; + int minor = start + i; + kdev_t devi = MKDEV (major, minor); + struct super_block *sb = get_super (devi); + sync_dev (devi); + if (sb) + invalidate_inodes (sb); + invalidate_buffers (devi); + } + dasd_destroy_partitions(device); + dasd_setup_partitions(device); + return rc; + +} +static int do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) { int rc = 0; @@ -2013,31 +2182,37 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u", _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no), device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev), - device->devinfo.devno, device->devinfo.irq, - data); + device->devinfo.devno, device->devinfo.irq, data); #endif switch (no) { + case DASDAPIVER: { + int ver = DASD_API_VERSION; + rc = copy_to_user ((int *) data, &ver, sizeof (int)); + if (rc) + rc = -EFAULT; + break; + } case BLKGETSIZE:{ /* Return device size */ - long blocks = blk_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)] << 1; - rc = copy_to_user ((long *) data, &blocks, sizeof (long)); + long blocks = major_info->gendisk.sizes + [MINOR (inp->i_rdev)] << 1; + rc = + copy_to_user ((long *) data, &blocks, + sizeof (long)); if (rc) rc = -EFAULT; break; } case BLKRRPART:{ - if (!capable(CAP_SYS_ADMIN)) { - rc = -EACCES; - break; - } - fsync_dev(inp->i_rdev); - dasd_partn_detect (device); - invalidate_buffers(inp->i_rdev); - rc = 0; + if (!capable (CAP_SYS_ADMIN)) { + rc = -EACCES; + break; + } + rc = dasd_revalidate (device); break; } case HDIO_GETGEO:{ - struct hd_geometry geo = {0,}; - rc = dasd_fillgeo(inp->i_rdev, &geo); + struct hd_geometry geo = { 0, }; + rc = dasd_fillgeo (inp->i_rdev, &geo); if (rc) break; @@ -2047,148 +2222,208 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) rc = -EFAULT; break; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - case BLKSSZGET: - case BLKROSET: - case BLKROGET: - case BLKRASET: - case BLKRAGET: - case BLKFLSBUF: - case BLKPG: - case BLKELVGET: - case BLKELVSET: - return blk_ioctl(inp->i_rdev, no, data); - break; -#else - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!dev || arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(dev)] = arg; - rc = 0; - break; - case BLKRAGET: - if (!arg) - return -EINVAL; - rc = put_user(read_ahead[MAJOR(dev)], (long *) arg); - break; - case BLKSSZGET: { - /* Block size of media */ - rc = copy_to_user((int *)data, - &blksize_size[MAJOR(device->kdev)] - [MINOR(device->kdev)], - sizeof(int)) ? -EFAULT : 0; + case BIODASDDISABLE:{ + if (!capable (CAP_SYS_ADMIN)) { + rc = -EACCES; + break; + } + if ( device->level > DASD_STATE_ACCEPT) { + if ( device->request_queue) + dasd_flush_request_queues(device,0); + dasd_flush_chanq(device,0); + dasd_disable_blkdev(device); + dasd_set_device_level (device->devinfo.devno, + device->discipline, + DASD_STATE_ACCEPT); + } + break; } - RO_IOCTLS (inp->i_rdev, data); - case BLKFLSBUF:{ - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - fsync_dev(inp->i_rdev); - invalidate_buffers(inp->i_rdev); - rc = 0; - break; + case BIODASDENABLE:{ + dasd_range_t range = { + from: device->devinfo.devno, + to: device->devinfo.devno + }; + if (!capable (CAP_SYS_ADMIN)) { + rc = -EACCES; + break; + } + dasd_enable_ranges (&range, device->discipline, 0); + break; } -#endif /* LINUX_IS_24 */ - case BIODASDRSID:{ - rc = copy_to_user ((void *) data, - &(device->devinfo.sid_data), - sizeof (senseid_t)) ? -EFAULT : 0; - break; - } - case BIODASDRWTB:{ - int offset = 0; - int xlt; - rc = copy_from_user (&xlt, (void *) data, - sizeof (int)) ? -EFAULT : 0; - if (rc) + case BIODASDFMT:{ + /* fdata == NULL is no longer a valid arg to dasd_format ! */ + int partn = MINOR (inp->i_rdev) & + ((1 << major_info->gendisk.minor_shift) - 1); + format_data_t fdata; + + if (!capable (CAP_SYS_ADMIN)) { + rc = -EACCES; break; - offset = major_info->gendisk.part[MINOR (inp->i_rdev)].start_sect >> - device->sizes.s2b_shift; - xlt += offset; - rc = copy_to_user ((void *) data, &xlt, - sizeof (int)) ? -EFAULT : 0; - break; - } - case BIODASDFORMAT:{ - /* fdata == NULL is a valid arg to dasd_format ! */ - int partn; - format_data_t fdata = - { - DASD_FORMAT_DEFAULT_START_UNIT, - DASD_FORMAT_DEFAULT_STOP_UNIT, - DASD_FORMAT_DEFAULT_BLOCKSIZE, - DASD_FORMAT_DEFAULT_INTENSITY}; - - if (!capable(CAP_SYS_ADMIN)) { - rc = -EACCES; - break; + } + if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) { + rc = -EROFS; + break; } - if (data) { - rc = copy_from_user (&fdata, (void *) data, - sizeof (format_data_t)); - if (rc) { - rc = -EFAULT; - break; - } + if (!data) { + rc = -EINVAL; + break; + } + rc = copy_from_user (&fdata, (void *) data, + sizeof (format_data_t)); + if (rc) { + rc = -EFAULT; + break; } - partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1); if (partn != 0) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Cannot low-level format a partition\n", - device->devinfo.devno, device->devinfo.irq, device->name, - MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "Cannot low-level format a partition"); return -EINVAL; } rc = dasd_format (device, &fdata); break; } + case BIODASDPRRST:{ + if (!capable (CAP_SYS_ADMIN)) { + rc = -EACCES; + break; + } + memset (&device->profile, 0, + sizeof (dasd_profile_info_t)); + break; + } + case BIODASDPRRD:{ + rc = copy_to_user((long *)data, + (long *)&device->profile, + sizeof(dasd_profile_info_t)); + if (rc) + rc = -EFAULT; + break; + } case BIODASDRSRV:{ - ccw_req_t *req; - if (!capable(CAP_SYS_ADMIN)) { - rc = -EACCES; - break; - } - req = device->discipline->reserve (device); - rc = sleep_on_req (req); - dasd_free_request (req); - break; - } + ccw_req_t *req; + if (!capable (CAP_SYS_ADMIN)) { + rc = -EACCES; + break; + } + req = device->discipline->reserve (device); + rc = dasd_sleep_on_req (req); + dasd_free_request (req, device); + break; + } case BIODASDRLSE:{ - ccw_req_t *req; - if (!capable(CAP_SYS_ADMIN)) { - rc = -EACCES; - break; - } - req = device->discipline->release (device); - rc = sleep_on_req (req); - dasd_free_request (req); - break; - } + ccw_req_t *req; + if (!capable (CAP_SYS_ADMIN)) { + rc = -EACCES; + break; + } + req = device->discipline->release (device); + rc = dasd_sleep_on_req (req); + dasd_free_request (req, device); + break; + } case BIODASDSLCK:{ printk (KERN_WARNING PRINTK_HEADER "Unsupported ioctl BIODASDSLCK\n"); break; } + case BIODASDINFO:{ + dasd_information_t dasd_info; + unsigned long flags; + rc = device->discipline->fill_info (device, &dasd_info); + dasd_info.label_block = device->sizes.pt_block; + dasd_info.devno = device->devinfo.devno; + dasd_info.schid = device->devinfo.irq; + dasd_info.cu_type = device->devinfo.sid_data.cu_type; + dasd_info.cu_model = device->devinfo.sid_data.cu_model; + dasd_info.dev_type = device->devinfo.sid_data.dev_type; + dasd_info.dev_model = device->devinfo.sid_data.dev_model; + dasd_info.open_count = + atomic_read (&device->open_count); + dasd_info.status = device->level; + if (device->discipline) { + memcpy (dasd_info.type, + device->discipline->name, 4); + } else { + memcpy (dasd_info.type, "none", 4); + } + dasd_info.req_queue_len = 0; + dasd_info.chanq_len = 0; + if (device->request_queue->request_fn) { + struct list_head *l; + ccw_req_t *cqr = device->queue.head; + spin_lock_irqsave (&io_request_lock, flags); + list_for_each (l, + &device->request_queue-> + queue_head) { + dasd_info.req_queue_len++; + } + spin_unlock_irqrestore (&io_request_lock, + flags); + s390irq_spin_lock_irqsave (device->devinfo.irq, + flags); + while (cqr) { + cqr = cqr->next; + dasd_info.chanq_len++; + } + s390irq_spin_unlock_irqrestore (device->devinfo. + irq, flags); + } + rc = + copy_to_user ((long *) data, (long *) &dasd_info, + sizeof (dasd_information_t)); + if (rc) + rc = -EFAULT; + break; + } +#if 0 /* needed for XFS */ + case BLKBSZSET:{ + int bsz; + rc = copy_from_user ((long *)&bsz,(long *)data,sizeof(int)); + if ( rc ) { + rc = -EFAULT; + } else { + if ( bsz >= device->sizes.bp_block ) + rc = blk_ioctl (inp->i_rdev, no, data); + else + rc = -EINVAL; + } + break; + } +#endif /* 0 */ + case BLKSSZGET: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKPG: + case BLKELVGET: + case BLKELVSET: + return blk_ioctl (inp->i_rdev, no, data); + break; default:{ - dasd_ioctl_list_t *old = dasd_find_ioctl(no); - if ( old ) { - rc = old->handler(inp,no,data); + dasd_ioctl_list_t *old = dasd_find_ioctl (no); + if (old) { + if ( old->owner ) + __MOD_INC_USE_COUNT(old->owner); + rc = old->handler (inp, no, data); + if ( old->owner ) + __MOD_DEC_USE_COUNT(old->owner); } else { DASD_MESSAGE (KERN_INFO, device, - "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n", + "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n", no, _IOC_DIR (no) == _IOC_NONE ? "0" : _IOC_DIR (no) == _IOC_READ ? "r" : - _IOC_DIR (no) == _IOC_WRITE ? "w" : - _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? - "rw" : "u", - _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no), + _IOC_DIR (no) == + _IOC_WRITE ? "w" : _IOC_DIR (no) + == (_IOC_READ | _IOC_WRITE) ? "rw" + : "u", _IOC_TYPE (no), + _IOC_NR (no), _IOC_SIZE (no), data); - rc = -EINVAL; - } + rc = -ENOTTY; + } break; } } @@ -2213,37 +2448,46 @@ static int dasd_open (struct inode *inp, struct file *filp) { int rc = 0; + unsigned long flags; dasd_device_t *device; + MOD_INC_USE_COUNT; if ((!inp) || !(inp->i_rdev)) { - return -EINVAL; + rc = -EINVAL; + goto fail; } if (dasd_probeonly) { - printk ("\n" KERN_INFO PRINTK_HEADER "No access to device (%d:%d) due to probeonly mode\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); - return -EPERM; + printk ("\n" KERN_INFO PRINTK_HEADER + "No access to device (%d:%d) due to probeonly mode\n", + MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); + rc = -EPERM; + goto fail; } + spin_lock_irqsave(&discipline_lock,flags); device = dasd_device_from_kdev (inp->i_rdev); - if (device == NULL) { + if (device == NULL ) { printk (KERN_WARNING PRINTK_HEADER - "No device registered as (%d:%d)\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); - return -ENODEV; + "No device registered as (%d:%d)\n", + MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); + rc = -ENODEV; + goto unlock; } - if (device->level < DASD_DEVICE_LEVEL_RECOGNIZED || - device->discipline == NULL) { + if (device->level < DASD_STATE_ACCEPT ) { DASD_MESSAGE (KERN_WARNING, device, " %s", " Cannot open unrecognized device\n"); - return -EINVAL; + rc = -ENODEV; + goto unlock; } - spin_lock(&dasd_open_count_lock); - if (device->open_count == -1) { - spin_unlock (&dasd_open_count_lock); - return -EBUSY; + if (atomic_inc_return (&device->open_count) == 1 ) { + if ( device->discipline->owner ) + __MOD_INC_USE_COUNT(device->discipline->owner); + } else { + MOD_DEC_USE_COUNT; } -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif /* MODULE */ - device->open_count++; - spin_unlock (&dasd_open_count_lock); + unlock: + spin_unlock_irqrestore(&discipline_lock,flags); + fail: + if (rc) MOD_DEC_USE_COUNT; return rc; } @@ -2251,28 +2495,41 @@ static int dasd_release (struct inode *inp, struct file *filp) { int rc = 0; + int count; dasd_device_t *device; if ((!inp) || !(inp->i_rdev)) { - return -EINVAL; + rc = -EINVAL; + goto out; } device = dasd_device_from_kdev (inp->i_rdev); if (device == NULL) { printk (KERN_WARNING PRINTK_HEADER "No device registered as %d:%d\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); - return -EINVAL; + rc = -EINVAL; + goto out; } - spin_lock(&dasd_open_count_lock); - if (device->open_count--) { -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif /* MODULE */ - } - fsync_dev(inp->i_rdev); /* sync the device */ - if (device->open_count == 0) /* finally invalidate buffers */ - invalidate_buffers(inp->i_rdev); - spin_unlock(&dasd_open_count_lock); + + if (device->level < DASD_STATE_ACCEPT ) { + DASD_MESSAGE (KERN_WARNING, device, + " %s", " Cannot release unrecognized device\n"); + rc = -ENODEV; + goto out; + } + fsync_dev (inp->i_rdev); /* sync the device */ + count = atomic_dec_return (&device->open_count); + if ( count == 0) { + invalidate_buffers (inp->i_rdev); + if ( device->discipline->owner ) + __MOD_DEC_USE_COUNT(device->discipline->owner); + MOD_DEC_USE_COUNT; + } else if ( count == -1 ) { /* paranoia only */ + atomic_set (&device->open_count,0); + printk (KERN_WARNING PRINTK_HEADER + "release called with open count==0\n"); + } + out: return rc; } @@ -2282,11 +2539,6 @@ block_device_operations dasd_device_operations = open:dasd_open, release:dasd_release, ioctl:dasd_ioctl, -#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - read:block_read, - write:block_write, - fsync:block_fsync, -#endif /* LINUX_IS_24 */ }; /* SECTION: Management of device list */ @@ -2298,16 +2550,9 @@ dasd_fillgeo(int kdev,struct hd_geometry *geo) return -EINVAL; device->discipline->fill_geometry (device, geo); - geo->start = device->major_info-> - gendisk.part[MINOR(kdev)].start_sect; - - /* This is a hack. dasdfmt and ibm.c expect geo.start - to contain the block number of the label block when - it calls HDIO_GETGEO on the first partition. */ - if (geo->start == 0) - geo->start = device->sizes.pt_block; - - return 0; + geo->start = device->major_info->gendisk.part[MINOR(kdev)].start_sect + >> device->sizes.s2b_shift;; + return 0; } @@ -2319,11 +2564,11 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd) char first, second, third; if (hd) { - major_info_t *major_info=NULL; + major_info_t *major_info = NULL; struct list_head *l; - list_for_each(l,&dasd_major_info[0].list) { - major_info = list_entry(l,major_info_t,list); + list_for_each (l, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); if (&major_info->gendisk == hd) { break; } @@ -2334,14 +2579,14 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd) } } third = index % 26; - second = ((index-26) / 26) % 26; - first = (((index-702) / 26) / 26) % 26; + second = ((index - 26) / 26) % 26; + first = (((index - 702) / 26) / 26) % 26; len = sprintf (str, "dasd"); - if (index>701) { + if (index > 701) { len += sprintf (str + len, "%c", first + 'a'); } - if (index>25) { + if (index > 25) { len += sprintf (str + len, "%c", second + 'a'); } len += sprintf (str + len, "%c", third + 'a'); @@ -2356,20 +2601,215 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd) return 0; } -#ifdef CONFIG_DASD_DYNAMIC static void -dasd_plug_device (dasd_device_t *device) +dasd_plug_device (dasd_device_t * device) +{ + atomic_set(&device->plugged,1); +} + +static void +dasd_unplug_device (dasd_device_t * device) +{ + atomic_set(&device->plugged,0); + dasd_schedule_bh(device); +} + +static void +dasd_flush_chanq ( dasd_device_t * device, int destroy ) +{ + ccw_req_t *cqr; + unsigned long flags; + if ( destroy ) { + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + cqr = device->queue.head; + while ( cqr != NULL ) { + if ( cqr -> status == CQR_STATUS_IN_IO ) + device->discipline->term_IO (cqr); + if ( cqr->status != CQR_STATUS_DONE || + cqr->status != CQR_STATUS_FAILED ) { + cqr->status = CQR_STATUS_FAILED; + } + dasd_schedule_bh(device); + cqr = cqr->next; + } + s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); + } + wait_event( device->wait_q, device->queue.head == NULL ); +} + +static void +dasd_flush_request_queues ( dasd_device_t * device, int destroy ) +{ + int i; + int major = MAJOR(device->kdev); + int minor = MINOR(device->kdev); + for ( i = 0; i < (1 << DASD_PARTN_BITS); i ++) { + if ( destroy ) + destroy_buffers(MKDEV(major,minor+i)); + else + invalidate_buffers(MKDEV(major,minor+i)); + } +} + +static int +dasd_disable_volume ( dasd_device_t * device, int force ) { - device->request_queue.plugged = 1; /* inhibit further calls of request_fn */ + int rc = 0; + int target = DASD_STATE_KNOWN; + int count = atomic_read (&device->open_count); + int part; + + if ( count ) { + DASD_MESSAGE (KERN_EMERG, device, "%s", + "device has vanished although it was open!"); + } + if ( force ) { + dasd_flush_chanq(device,force); + dasd_flush_request_queues(device,force); + dasd_disable_blkdev(device); + target = DASD_STATE_DEL; + } + +#if 0 + /* unregister devfs entries */ + for (part = 0; part < (1 << DASD_PARTN_BITS); part++) { + devfs_unregister(device->major_info->gendisk.part[MINOR(device->kdev)+part].de); + device->major_info->gendisk.part[MINOR(device->kdev)+part].de = NULL; + } +#endif + + DASD_MESSAGE (KERN_WARNING, device, + "disabling device, target state:%d",target); + dasd_set_device_level (device->devinfo.devno, + device->discipline, + target); + return rc; } static void -dasd_unplug_device (dasd_device_t *device) +dasd_disable_ranges (dasd_range_t *range, + dasd_discipline_t *d, + int all, int force ) { - generic_unplug_device(&device->request_queue); + dasd_range_t *rrange; + int j; + + if (range == &dasd_range_head) { + rrange = list_entry (range->list.next, + dasd_range_t, list); + } else { + rrange = range; + } + do { + for (j = rrange->from; j <= rrange->to; j++) { + dasd_device_t **dptr; + dasd_device_t *device; + dptr = dasd_device_from_devno(j); + if ( dptr == NULL ) { + continue; + } + device = *dptr; + if (device == NULL || + (d != NULL && + device -> discipline != d)) + continue; + + dasd_disable_volume(device, force); + } + rrange = list_entry (rrange->list.next, dasd_range_t, list); + } while ( all && rrange && rrange != range ); +} + +static void +dasd_enable_single_device ( unsigned long arg ) { + dasd_device_t * device =(dasd_device_t *) arg; + int devno = device->devinfo.devno; + dasd_range_t range = { from: devno, to:devno }; + dasd_enable_ranges (&range,NULL,0); } static void +dasd_enable_ranges (dasd_range_t *range, dasd_discipline_t *d, int all ) +{ + int retries = 0; + int j; + kdev_t tempdev; + dasd_range_t *rrange; + + if (range == NULL) + return; + + do { + if (range == &dasd_range_head) { + rrange = list_entry (range->list.next, + dasd_range_t, list); + } else { + rrange = range; + } + do { + for (j = rrange->from; j <= rrange->to; j++) { + if ( dasd_devindex_from_devno(j) < 0 ) + continue; + dasd_set_device_level (j, d, DASD_STATE_ONLINE); + } + rrange = list_entry (rrange->list.next, dasd_range_t, list); + } while ( all && rrange && rrange != range ); + + if (atomic_read (&dasd_init_pending) == 0) /* we are done, exit loop */ + break; + + if ( retries == 0 ) { + printk (KERN_INFO PRINTK_HEADER + "waiting for responses...\n"); + } else if ( retries < 5 ) { + printk (KERN_INFO PRINTK_HEADER + "waiting a little bit longer...\n"); + } else { + printk (KERN_INFO PRINTK_HEADER + "giving up, enable late devices manually!\n"); + break; + } + interruptible_sleep_on_timeout (&dasd_init_waitq, (1 * HZ)); + retries ++; + } while (1); + /* now setup block devices */ + + /* Now do block device and partition setup */ + if (range == &dasd_range_head) { + rrange = list_entry (range->list.next, + dasd_range_t, list); + } else { + rrange = range; + } + do { + for (j = rrange->from; j <= rrange->to; j++) { + dasd_device_t **dptr; + dasd_device_t *device; + if ( dasd_devindex_from_devno(j) < 0 ) + continue; + dptr = dasd_device_from_devno(j); + device = *dptr; + if (device == NULL ) + continue; + if ( ((d == NULL && device->discipline != NULL) || + (device->discipline == d )) && + device->level >= DASD_STATE_READY && + device->request_queue == NULL ) { + if (dasd_features_from_devno(j)&DASD_FEATURE_READONLY) { + for (tempdev=device->kdev;tempdev<(device->kdev +(1 << DASD_PARTN_BITS));tempdev++) + set_device_ro (tempdev, 1); + printk (KERN_WARNING PRINTK_HEADER "setting read-only mode for device /dev/%s\n",device->name); + } + dasd_setup_blkdev(device); + dasd_setup_partitions(device); + } + } + rrange = list_entry (rrange->list.next, dasd_range_t, list); + } while ( all && rrange && rrange != range ); +} + +#ifdef CONFIG_DASD_DYNAMIC +static void dasd_not_oper_handler (int irq, int status) { dasd_device_t *device = NULL; @@ -2377,13 +2817,12 @@ dasd_not_oper_handler (int irq, int status) struct list_head *l; int i, devno = -ENODEV; - /* find out devno of leaving device: CIO has already deleted this information ! */ - list_for_each(l,&dasd_major_info[0].list) { - major_info=list_entry(l, major_info_t,list); + /* find out devno of leaving device: CIO has already deleted this information ! */ + list_for_each (l, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); for (i = 0; i < DASD_PER_MAJOR; i++) { device = major_info->dasd_device[i]; - if (device && - device->devinfo.irq == irq) { + if (device && device->devinfo.irq == irq) { devno = device->devinfo.devno; break; } @@ -2396,360 +2835,561 @@ dasd_not_oper_handler (int irq, int status) "not_oper_handler called on irq %d no devno!\n", irq); return; } - - if (device->open_count != 0) { - DASD_MESSAGE(KERN_ALERT,device,"%s", - "open device has gone. please repair!"); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, - NULL, 0); - } else { - DASD_MESSAGE(KERN_INFO,device,"%s","device has gone"); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, - NULL, 0); - } -} - -static int -dasd_enable_single_volume (int irq) -{ - int rc = 0; - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, - NULL, 0); - printk (KERN_INFO PRINTK_HEADER "waiting for response...\n"); - { - static wait_queue_head_t wait_queue; - init_waitqueue_head (&wait_queue); - interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1); - } - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); - return rc; + dasd_disable_volume(device, 0); } int dasd_oper_handler (int irq, devreg_t * devreg) { int devno; - int rc; - devno = get_devno_by_irq (irq); - printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n"); - if (devno == -ENODEV) { - printk (KERN_WARNING PRINTK_HEADER "NODEV\n"); - return -ENODEV; - } - if (dasd_autodetect) { - dasd_add_range (devno, 0); - } - rc = dasd_enable_single_volume (irq); - return rc; -} -#endif /* CONFIG_DASD_DYNAMIC */ - -/* - * function dasd_set_device_level - */ -static int -dasd_set_device_level (unsigned int irq, int desired_level, - dasd_discipline_t * discipline, int flags) -{ int rc = 0; - int devno; - dasd_device_t **device_addr, *device; - int current_level; major_info_t *major_info = NULL; + dasd_range_t *rptr,range; + dasd_device_t *device = NULL; struct list_head *l; - int i, minor, major; - ccw_req_t *cqr = NULL; - struct gendisk *dd; + int i; devno = get_devno_by_irq (irq); - if (devno < 0) { /* e.g. when device has been detached before */ - /* search in device list */ - list_for_each(l,&dasd_major_info[0].list) { - major_info = list_entry(l,major_info_t,list); - for (i = 0; i < DASD_PER_MAJOR; i++) { - device = major_info->dasd_device[i]; - if (device && device->devinfo.irq == irq) { - devno = device->devinfo.devno; - break; - } + if (devno == -ENODEV) { + rc = -ENODEV; + goto out; + } + /* find out devno of leaving device: CIO has already deleted this information ! */ + list_for_each (l, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); + for (i = 0; i < DASD_PER_MAJOR; i++) { + device = major_info->dasd_device[i]; + if (device && device->devinfo.irq == irq) { + devno = device->devinfo.devno; + break; } - if (devno == -ENODEV) - return -ENODEV; } + if (devno != -ENODEV) + break; } - if (dasd_devindex_from_devno (devno) < 0) { - return -ENODEV; + if (devno < 0) { + BUG(); + } + if ( device && + device->level == DASD_STATE_READY ) { + dasd_set_device_level (device->devinfo.devno, + device->discipline, DASD_STATE_ONLINE); + + } else { + if (dasd_autodetect) { + rptr = dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES); + if ( rptr == NULL ) { + rc = -ENOMEM; + goto out; + } + } else { + range.from = devno; + range.to = devno; + rptr = ⦥ + } + dasd_enable_ranges (rptr, NULL, 0); + } + out: + return rc; +} +#endif /* CONFIG_DASD_DYNAMIC */ + +static inline dasd_device_t ** +dasd_find_device_addr ( int devno ) +{ + dasd_device_t **device_addr; + + DASD_DRIVER_DEBUG_EVENT (1, dasd_find_device_addr, + "devno %04X", devno); + if ( dasd_devindex_from_devno (devno) < 0 ) { + DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, + "no dasd: devno %04X", + devno); + return NULL; } + /* allocate major numbers on demand for new devices */ while ((device_addr = dasd_device_from_devno (devno)) == NULL) { - if ((rc = dasd_register_major (NULL)) > 0) { - printk (KERN_INFO PRINTK_HEADER - "Registered to major number: %u\n", rc); - } else { - printk (KERN_WARNING PRINTK_HEADER - "Couldn't register to another major no\n"); - return -ERANGE; + int rc; + + if ((rc = dasd_register_major (NULL)) <= 0) { + + DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, + "%s", + "out of major numbers!"); + break; } } - device = *device_addr; - if (!device) { /* allocate device descriptor */ - device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC); - if (!device) { - printk (KERN_WARNING PRINTK_HEADER " No memory for device descriptor\n"); - goto nomem; + return device_addr; +} + +static inline int +dasd_state_del_to_new (dasd_device_t **addr ) +{ + dasd_device_t* device; + int rc = 0; + if (*addr == NULL) { /* allocate device descriptor on demand for new device */ + device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC); + if (device == NULL ) { + rc = -ENOMEM; + goto out; } memset (device, 0, sizeof (dasd_device_t)); - *device_addr = device; + *addr = device; + device->lowmem_ccws = (void*)get_free_page (GFP_ATOMIC|GFP_DMA); + if (device->lowmem_ccws == NULL) { + rc = -ENOMEM; + goto noccw; } - list_for_each(l,&dasd_major_info[0].list) { - int i; - major_info = list_entry(l,major_info_t,list); +#ifdef CONFIG_ARCH_S390X + device->lowmem_idals = + device->lowmem_idal_ptr = (void*) get_free_page (GFP_ATOMIC|GFP_DMA); + if (device->lowmem_idals == NULL) { + rc = -ENOMEM; + goto noidal; + } +#endif +} + goto out; + noidal: + free_page ((long) device->lowmem_ccws); + noccw: + kfree(device); + out: + return rc; +} + +static inline int +dasd_state_new_to_del (dasd_device_t **addr ) +{ + dasd_device_t *device = *addr; + if (device && device->private) { + kfree(device->private); + device->private = NULL; + } +#ifdef CONFIG_ARCH_S390X + free_page ((long)(device->lowmem_idals)); +#endif + free_page((long)(device->lowmem_ccws)); + kfree(device); + *addr = NULL; + return 0; +} + +static inline int +dasd_state_new_to_known (dasd_device_t **dptr, int devno, dasd_discipline_t *disc) +{ + int rc = 0; + umode_t devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR; + struct list_head *l; + major_info_t *major_info = NULL; + int i; + dasd_device_t *device = *dptr; + devfs_handle_t dir; + char buffer[5]; + + + list_for_each (l, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); for (i = 0; i < DASD_PER_MAJOR; i++) { if (major_info->dasd_device[i] == device) { - device->kdev = MKDEV (major_info->gendisk.major, i << DASD_PARTN_BITS); + device->kdev = MKDEV (major_info->gendisk.major, + i << DASD_PARTN_BITS); break; } } - if (i < DASD_PER_MAJOR) + if (i < DASD_PER_MAJOR) /* we found one */ break; } - if (major_info == &dasd_major_info[0]) { - return -ENODEV; - } - minor = MINOR (device->kdev); - major = MAJOR (device->kdev); - current_level = device->level; - if (desired_level > current_level) { - switch (current_level) { - case DASD_DEVICE_LEVEL_UNKNOWN: /* Find a discipline */ - device->major_info = major_info; - dasd_device_name (device->name, - ((long) device_addr - - (long) device->major_info->dasd_device) / - sizeof (dasd_device_t *), - 0, &major_info->gendisk); - rc = get_dev_info_by_irq (irq, &device->devinfo); - if (rc < 0) { - break; - } - discipline = dasd_find_discipline (device); - if (discipline && !rc) { - DASD_MESSAGE (KERN_INFO, device, - "%s", " "); - } else { + if ( major_info == NULL || major_info == &dasd_major_info[0] ) + BUG(); + + device->major_info = major_info; + dasd_device_name (device->name, + (((long)dptr - + (long)device->major_info->dasd_device) / + sizeof (dasd_device_t *)), + 0, &device->major_info->gendisk); + init_waitqueue_head (&device->wait_q); + + rc = get_dev_info_by_devno (devno, &device->devinfo); + if ( rc ) { + goto out; + } + if ( devno != device->devinfo.devno ) + BUG(); + device->discipline = dasd_find_disc (device, disc); + if ( device->discipline == NULL ) { + rc = -ENODEV; + goto out; + } + sprintf (buffer, "%04x", device->devinfo.devno); + dir = devfs_mk_dir (dasd_devfs_handle, buffer, device); + device->major_info->gendisk.de_arr[MINOR(device->kdev) + >> DASD_PARTN_BITS] = dir; + if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) { + devfs_perm &= ~(S_IWUSR); + } + device->devfs_entry = devfs_register (dir,"device",DEVFS_FL_DEFAULT, + MAJOR(device->kdev), + MINOR(device->kdev), + devfs_perm, + &dasd_device_operations,NULL); + device->level = DASD_STATE_KNOWN; + out: + return rc; +} + +static inline int +dasd_state_known_to_new (dasd_device_t *device ) +{ + int rc = 0; + /* don't reset to zeros because of persistent data durich detach/attach! */ + devfs_unregister(device->devfs_entry); + devfs_unregister(device->major_info->gendisk.de_arr[MINOR(device->kdev) >> DASD_PARTN_BITS]); + + return rc; +} + +static inline int +dasd_state_known_to_accept (dasd_device_t *device) +{ + int rc = 0; + device->debug_area = debug_register (device->name, 0, 2, + 3 * sizeof (long)); + debug_register_view (device->debug_area, &debug_sprintf_view); + debug_register_view (device->debug_area, &debug_hex_ascii_view); + DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area created",device); + + if (device->discipline->int_handler) { + rc = s390_request_irq_special (device->devinfo.irq, + device->discipline->int_handler, + dasd_not_oper_handler, + 0, DASD_NAME, + &device->dev_status); + if ( rc ) { + printk("No request IRQ\n"); + goto out; + } + } + device->level = DASD_STATE_ACCEPT; + out: + return rc; +} + +static inline int +dasd_state_accept_to_known (dasd_device_t *device ) +{ + if ( device->discipline == NULL ) + goto out; + if (device->discipline->int_handler) { + free_irq (device->devinfo.irq, &device->dev_status); + } + DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area deleted",device); + if ( device->debug_area != NULL ) + debug_unregister (device->debug_area); + device->discipline = NULL; + device->level = DASD_STATE_KNOWN; + out: + return 0; +} + +static inline int +dasd_state_accept_to_init (dasd_device_t *device) +{ + int rc = 0; + unsigned long flags; + + if ( device->discipline->init_analysis ) { + device->init_cqr=device->discipline->init_analysis (device); + if ( device->init_cqr != NULL ) { + if ( device->discipline->start_IO == NULL ) + BUG(); + atomic_inc (&dasd_init_pending); + s390irq_spin_lock_irqsave (device->devinfo.irq, + flags); + rc = device->discipline->start_IO (device->init_cqr); + s390irq_spin_unlock_irqrestore(device->devinfo.irq, + flags); + if ( rc ) + goto out; + device->level = DASD_STATE_INIT; + } else { + rc = -ENOMEM; + } + } else { + rc = dasd_state_init_to_ready ( device ); + } + out: + return rc; +} + +static inline int +dasd_state_init_to_ready (dasd_device_t *device ) +{ + int rc = 0; + if (device->discipline->do_analysis != NULL) + if ( device->discipline->do_analysis (device) == 0 ) + switch (device->sizes.bp_block) { + case 512: + case 1024: + case 2048: + case 4096: break; - } - device->discipline = discipline; - device->debug_area = debug_register(device->name,0,2,3*sizeof(long)); - debug_register_view(device->debug_area,&debug_sprintf_view); - debug_register_view(device->debug_area,&debug_hex_ascii_view); - if (device->discipline->int_handler) { -#ifdef CONFIG_DASD_DYNAMIC - s390_request_irq_special (irq, - device->discipline->int_handler, - dasd_not_oper_handler, - 0, - DASD_NAME, - &device->dev_status); -#else /* !defined(CONFIG_DASD_DYNAMIC) */ - request_irq (irq, - device->discipline->int_handler, - 0, - DASD_NAME, - &device->dev_status); -#endif /* CONFIG_DASD_DYNAMIC */ - } - device->proc_dir = (struct proc_dir_entry *) - kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL); - if (device->proc_dir) { - memset (device->proc_dir, 0, sizeof (struct proc_dir_entry)); - device->proc_info = (struct proc_dir_entry *) - kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL); - if (device->proc_info) { - memset (device->proc_info, 0, - sizeof (struct proc_dir_entry)); - } - device->proc_stats = (struct proc_dir_entry *) - kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL); - if (device->proc_stats) { - memset (device->proc_stats, 0, - sizeof (struct proc_dir_entry)); - } - } - init_waitqueue_head (&device->wait_q); - check_then_set (&device->level, - DASD_DEVICE_LEVEL_UNKNOWN, - DASD_DEVICE_LEVEL_RECOGNIZED); - if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED) - break; - case DASD_DEVICE_LEVEL_RECOGNIZED: /* Fallthrough ?? */ - if (device->discipline->init_analysis) { - cqr = device->discipline->init_analysis (device); - if (cqr != NULL) { - dasd_chanq_enq (&device->queue, cqr); - if (device->discipline->start_IO) { - long flags; - s390irq_spin_lock_irqsave (irq, flags); - device->discipline->start_IO (cqr); - check_then_set (&device->level, - DASD_DEVICE_LEVEL_RECOGNIZED, - DASD_DEVICE_LEVEL_ANALYSIS_PENDING); - s390irq_spin_unlock_irqrestore (irq, flags); - } - } - } else { - check_then_set (&device->level, DASD_DEVICE_LEVEL_RECOGNIZED, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); - } - if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING) - break; - case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: /* Fallthrough ?? */ - return -EAGAIN; - case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: /* Re-entering here ! */ - if (device->discipline->do_analysis) - if (device->discipline->do_analysis (device)) - return -ENODEV; - switch (device->sizes.bp_block) { - case 512: - case 1024: - case 2048: - case 4096: - break; - default: - { - printk (KERN_INFO PRINTK_HEADER - "/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes" - " Did you format the drive?\n", - device->name, devno, device->sizes.bp_block); - return -EMEDIUMTYPE; - } - } - blk_init_queue (&device->request_queue, do_dasd_request); - blk_queue_headactive (&device->request_queue, 0); - elevator_init(&device->request_queue.elevator, ELEVATOR_NOOP); - for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - if (i == 0) - blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1; - else - blk_size[major][minor + i] = 0; - hardsect_size[major][minor + i] = device->sizes.bp_block; - blksize_size[major][minor + i] = device->sizes.bp_block; - if (blksize_size[major][minor + i] < 1024) - blksize_size[major][minor + i] = 1024; - - max_sectors[major][minor + i] = - device->discipline->max_blocks << device->sizes.s2b_shift; - } - check_then_set (&device->level, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, - DASD_DEVICE_LEVEL_ANALYSED); - dd = &major_info->gendisk; - dd->sizes[minor] = (device->sizes.blocks << - device->sizes.s2b_shift) >> 1; - dd->part[minor].start_sect = 0; - { - char buffer[5]; - sprintf(buffer,"%04X",device->devinfo.devno); - dd->de_arr[minor>>DASD_PARTN_BITS] = devfs_mk_dir(dasd_devfs_handle,buffer,NULL); - } -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -#ifndef MODULE - if (flags & 0x80) + default: + rc = -EMEDIUMTYPE; + } + if ( device->init_cqr ) { + atomic_dec(&dasd_init_pending); + device->init_cqr = NULL; /* This one is no longer needed */ + } + device->level = DASD_STATE_READY; + return rc; +} + +static inline int +dasd_state_ready_to_accept (dasd_device_t *device ) +{ + int rc = 0; + unsigned long flags; + + if ( device->init_cqr != NULL ) { + if ( device->discipline->term_IO == NULL ) + BUG(); + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + device->discipline->term_IO (device->init_cqr); + s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags); + atomic_dec (&dasd_init_pending); + dasd_free_request (device->init_cqr, device); + device->init_cqr = NULL; + } + memset(&device->sizes,0,sizeof(dasd_sizes_t)); + device->level = DASD_STATE_ACCEPT; + return rc; +} + +static inline int +dasd_state_ready_to_online (dasd_device_t *device ) +{ + int rc = 0; + dasd_unplug_device (device); + device->level = DASD_STATE_ONLINE; + return rc; +} + +static inline int +dasd_state_online_to_ready (dasd_device_t *device ) +{ + int rc = 0; + dasd_plug_device (device); + device->level = DASD_STATE_READY; + return rc; +} + +static inline int +dasd_setup_blkdev (dasd_device_t *device ) +{ + int rc = 0; + int i; + int major = MAJOR(device->kdev); + int minor = MINOR(device->kdev); + + for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { + if (i == 0) + device->major_info->gendisk.sizes[minor] = + (device->sizes.blocks << device-> + sizes.s2b_shift) >> 1; + else + device->major_info->gendisk.sizes[minor + i] = 0; + hardsect_size[major][minor + i] = device->sizes.bp_block; + blksize_size[major][minor + i] = device->sizes.bp_block; + max_sectors[major][minor + i] = + device->discipline->max_blocks << + device->sizes.s2b_shift; + device->major_info->gendisk.part[minor+i].start_sect = 0; + device->major_info->gendisk.part[minor+i].nr_sects = 0; + } + device->request_queue = kmalloc(sizeof(request_queue_t),GFP_KERNEL); + device->request_queue->queuedata = device; + blk_init_queue (device->request_queue, do_dasd_request); + blk_queue_headactive (device->request_queue, 0); + elevator_init (&(device->request_queue->elevator),ELEVATOR_NOOP); + return rc; +} + +static inline int +dasd_disable_blkdev (dasd_device_t *device ) +{ + int i; + int major = MAJOR(device->kdev); + int minor = MINOR(device->kdev); + + for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { + destroy_buffers(MKDEV(major,minor+i)); + device->major_info->gendisk.sizes[minor + i] = 0; + hardsect_size[major][minor + i] = 0; + blksize_size[major][minor + i] = 0; + max_sectors[major][minor + i] = 0; + } + if (device->request_queue) { + blk_cleanup_queue (device->request_queue); + kfree(device->request_queue); + device->request_queue = NULL; + } + return 0; +} + + +/* + * function dasd_setup_partitions + * calls the function in genhd, which is appropriate to setup a partitioned disk + */ +static inline void +dasd_setup_partitions ( dasd_device_t * device ) +{ + register_disk (&device->major_info->gendisk, + device->kdev, + 1 << DASD_PARTN_BITS, + &dasd_device_operations, + (device->sizes.blocks << device->sizes.s2b_shift)); +} + +static inline void +dasd_destroy_partitions ( dasd_device_t * device ) +{ + int i; + int major = MAJOR(device->kdev); + int minor = MINOR(device->kdev); + + for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { + device->major_info->gendisk.part[minor+i].start_sect = 0; + device->major_info->gendisk.part[minor+i].nr_sects = 0; + } + devfs_register_partitions(&device->major_info->gendisk, + MINOR(device->kdev),1); +} + +static inline void +dasd_resetup_partitions ( dasd_device_t * device ) +{ + BUG(); + dasd_destroy_partitions ( device ) ; + dasd_setup_partitions ( device ) ; +} + +/* + * function dasd_set_device_level + */ +static int +dasd_set_device_level (unsigned int devno, + dasd_discipline_t * discipline, + int to_state) +{ + int rc = 0; + dasd_device_t **device_addr; + dasd_device_t *device; + int from_state; + + device_addr = dasd_find_device_addr ( devno ); + if ( device_addr == NULL ) { + rc = -ENODEV; + goto out; + } + device = *device_addr; + + if ( device == NULL ) { + from_state = DASD_STATE_DEL; + if ( to_state == DASD_STATE_DEL ) + goto out; + } else { + from_state = device->level; + } + + if ( from_state == to_state ) + goto out; + + if ( to_state < from_state ) + goto shutdown; + + /* First check for bringup */ + if ( from_state <= DASD_STATE_DEL && + to_state >= DASD_STATE_NEW ) { + rc = dasd_state_del_to_new(device_addr); + if ( rc ) { + goto bringup_fail; + } + device = *device_addr; + } + if ( from_state <= DASD_STATE_NEW && + to_state >= DASD_STATE_KNOWN ) { + rc = dasd_state_new_to_known( device_addr, devno, discipline ); + if ( rc ) { + goto bringup_fail; + } + } + if ( from_state <= DASD_STATE_KNOWN && + to_state >= DASD_STATE_ACCEPT ) { + rc = dasd_state_known_to_accept(device); + if ( rc ) { + goto bringup_fail; + } + } + if ( dasd_probeonly ) { + goto out; + } + if ( from_state <= DASD_STATE_ACCEPT && + to_state >= DASD_STATE_INIT ) { + rc = dasd_state_accept_to_init(device); + if ( rc ) { + goto bringup_fail; + } + } + if ( from_state <= DASD_STATE_INIT && + to_state >= DASD_STATE_READY ) { + rc = -EAGAIN; + goto out; + } + if ( from_state <= DASD_STATE_READY && + to_state >= DASD_STATE_ONLINE ) { + rc = dasd_state_ready_to_online(device); + if ( rc ) { + goto bringup_fail; + } + } + goto out; + bringup_fail: /* revert changes */ +#if 0 + printk (KERN_DEBUG PRINTK_HEADER + "failed to set device from state %d to %d at level %d rc %d. Reverting...\n", + from_state,to_state,device->level,rc); #endif -#endif /* KERNEL_VERSION */ - dasd_partn_detect (device); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) - break; - case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ - dasd_unplug_device(device); - check_then_set (&device->level, - DASD_DEVICE_LEVEL_ANALYSED, - DASD_DEVICE_LEVEL_ONLINE); - - if (desired_level == DASD_DEVICE_LEVEL_ONLINE) - break; - case DASD_DEVICE_LEVEL_ONLINE: - break; - default: - printk (KERN_WARNING PRINTK_HEADER - "Internal error in " __FILE__ " on line %d." - " validate_dasd called from %p with " - " desired_level = %d, current_level =%d" - " Pls send this message and your System.map to" - " linux390@de.ibm.com\n", - __LINE__, __builtin_return_address (0), - desired_level, current_level); - break; - } - } else if (desired_level < current_level) { /* donwgrade device status */ - switch (current_level) { - case DASD_DEVICE_LEVEL_ONLINE: /* Fallthrough ?? */ - dasd_plug_device(device); - check_then_set (&device->level, - DASD_DEVICE_LEVEL_ONLINE, - DASD_DEVICE_LEVEL_ANALYSED); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) - break; - case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ - for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - __invalidate_buffers(MKDEV(major,minor),1); - blk_size[major][minor] = 0; - hardsect_size[major][minor + i] = 0; - blksize_size[major][minor + i] = 0; - max_sectors[major][minor + i] = 0; - } - memset (&device->sizes, 0, sizeof (dasd_sizes_t)); - blk_cleanup_queue (&device->request_queue); - check_then_set (&device->level, - DASD_DEVICE_LEVEL_ANALYSED, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED) - break; - case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: - check_then_set (&device->level, - DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, - DASD_DEVICE_LEVEL_ANALYSIS_PENDING); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING) - break; - case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: /* Fallthrough ?? */ - check_then_set (&device->level, - DASD_DEVICE_LEVEL_ANALYSIS_PENDING, - DASD_DEVICE_LEVEL_RECOGNIZED); - if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED) - break; - case DASD_DEVICE_LEVEL_RECOGNIZED: /* Fallthrough ?? */ - if (device->discipline->int_handler) { - free_irq (irq, &device->dev_status); - } - device->discipline = NULL; - debug_unregister(device->debug_area); - check_then_set (&device->level, - DASD_DEVICE_LEVEL_RECOGNIZED, - DASD_DEVICE_LEVEL_UNKNOWN); - *device_addr = NULL; - kfree(device); - if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN) - break; - case DASD_DEVICE_LEVEL_UNKNOWN: - break; - default: - printk (KERN_WARNING PRINTK_HEADER - "Internal error in " __FILE__ " on line %d." - " validate_dasd called from %p with " - " desired_level = %d, current_level =%d" - " Pls send this message and your System.map to" - " linux390@de.ibm.com\n", - __LINE__, __builtin_return_address (0), - desired_level, current_level); - break; - } - } - if (rc) { - goto exit; - } - nomem: - rc = -ENOMEM; - exit: - return 0; + to_state = from_state; + from_state = device->level; + + /* now do a shutdown */ + shutdown: + if ( from_state >= DASD_STATE_ONLINE && + to_state <= DASD_STATE_READY ) + if (dasd_state_online_to_ready(device)) + BUG(); + if ( from_state >= DASD_STATE_READY && + to_state <= DASD_STATE_ACCEPT ) + if ( dasd_state_ready_to_accept(device)) + BUG(); + if ( from_state >= DASD_STATE_ACCEPT && + to_state <= DASD_STATE_KNOWN ) + if ( dasd_state_accept_to_known(device)) + BUG(); + if ( from_state >= DASD_STATE_KNOWN && + to_state <= DASD_STATE_NEW ) + if ( dasd_state_known_to_new(device)) + BUG(); + if ( from_state >= DASD_STATE_NEW && + to_state <= DASD_STATE_DEL) + if (dasd_state_new_to_del(device_addr)) + BUG(); + goto out; + out: + return rc; } /* SECTION: Procfs stuff */ @@ -2758,29 +3398,16 @@ typedef struct { int len; } tempinfo_t; -void dasd_fill_inode (struct inode* inode, int fill) { - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; +void +dasd_fill_inode (struct inode *inode, int fill) +{ + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct proc_dir_entry *dasd_proc_root_entry = NULL; -#else -static struct proc_dir_entry dasd_proc_root_entry = -{ - low_ino:0, - namelen:4, - name:"dasd", - mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP, - nlink:1, - uid:0, - gid:0, - size:0, - fill_inode:dasd_fill_inode -}; -#endif /* KERNEL_VERSION */ static struct proc_dir_entry *dasd_devices_entry; static struct proc_dir_entry *dasd_statistics_entry; @@ -2790,94 +3417,138 @@ dasd_devices_open (struct inode *inode, struct file *file) int rc = 0; int size = 1; int len = 0; - major_info_t *temp = dasd_major_info; + major_info_t *temp = NULL; struct list_head *l; tempinfo_t *info; int i; + unsigned long flags; + int index = 0; + MOD_INC_USE_COUNT; + spin_lock_irqsave(&discipline_lock,flags); info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t)); if (info == NULL) { - printk (KERN_WARNING "No memory available for data\n"); - return -ENOMEM; + printk (KERN_WARNING "No memory available for data\n"); + MOD_DEC_USE_COUNT; + return -ENOMEM; } else { file->private_data = (void *) info; } - list_for_each(l,&dasd_major_info[0].list) { - temp = list_entry(l,major_info_t,list); - for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { - dasd_device_t *device = temp->dasd_device[i]; - if (device) { - size += 128; - } - } + list_for_each (l, &dasd_major_info[0].list) { + size += 128 * 1 << (MINORBITS - DASD_PARTN_BITS); } - temp = dasd_major_info; - info->data = (char *) vmalloc (size); /* FIXME! determine space needed in a better way */ + info->data = (char *) vmalloc (size); + DASD_DRIVER_DEBUG_EVENT (1, dasd_devices_open, "area: %p, size 0x%x", + info->data, size); if (size && info->data == NULL) { printk (KERN_WARNING "No memory available for data\n"); vfree (info); + MOD_DEC_USE_COUNT; return -ENOMEM; } - list_for_each(l,&dasd_major_info[0].list) { - temp = list_entry(l,major_info_t,list); + list_for_each (l, &dasd_major_info[0].list) { + temp = list_entry (l, major_info_t, list); for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { - dasd_device_t *device = temp->dasd_device[i]; + dasd_device_t *device; + int devno = dasd_devno_from_devindex(index+i); + if ( devno == -ENODEV ) + continue; + device = temp->dasd_device[i]; if (device) { len += sprintf (info->data + len, - "%04X(%s) at (%d:%d) is %7s:", + "%04X(%s) at (%3d:%3d) is %7s:", device->devinfo.devno, - device->discipline ? device->discipline->name : "none", - temp->gendisk.major, i << DASD_PARTN_BITS, + device->discipline ? + device-> + discipline->name : "none", + temp->gendisk.major, + i << DASD_PARTN_BITS, device->name); switch (device->level) { - case DASD_DEVICE_LEVEL_UNKNOWN: - len += sprintf (info->data + len, "unknown\n"); - break; - case DASD_DEVICE_LEVEL_RECOGNIZED: - len += sprintf (info->data + len, "passive"); - len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n", - device->sizes.bp_block, - device->sizes.blocks, - ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11); - break; - case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: - len += sprintf (info->data + len, "busy \n"); + case DASD_STATE_NEW: + len += + sprintf (info->data + len, + "new"); + break; + case DASD_STATE_KNOWN: + len += + sprintf (info->data + len, + "detected"); break; - case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: - len += sprintf (info->data + len, "n/f \n"); + case DASD_STATE_ACCEPT: + len += sprintf (info->data + len,"accepted"); break; - case DASD_DEVICE_LEVEL_ANALYSED: - len += sprintf (info->data + len, "active "); - len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n", - device->sizes.bp_block, - device->sizes.blocks, - ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11); + case DASD_STATE_INIT: + len += + sprintf (info->data + len, + "busy "); break; - case DASD_DEVICE_LEVEL_ONLINE: - len += sprintf (info->data + len, "active "); - len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n", - device->sizes.bp_block, - device->sizes.blocks, - ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11); + case DASD_STATE_READY: + case DASD_STATE_ONLINE: + if ( atomic_read(&device->plugged) ) + len += + sprintf (info->data + len, + "fenced "); + else + len += + sprintf (info->data + len, + "active "); + if ( device->sizes.bp_block == 512 || + device->sizes.bp_block == 1024 || + device->sizes.bp_block == 2048 || + device->sizes.bp_block == 4096 ) + len += + sprintf (info->data + len, + "at blocksize: %d, %ld blocks, %ld MB", + device->sizes.bp_block, + device->sizes.blocks, + ((device-> + sizes.bp_block >> 9) * + device->sizes. + blocks) >> 11); + else + len += + sprintf (info->data + len, + "n/f "); break; default: - len += sprintf (info->data + len, "no stat\n"); + len += + sprintf (info->data + len, + "no stat"); break; } - } + } else { + char buffer[7]; + dasd_device_name (buffer, i, 0, &temp->gendisk); + if ( devno < 0 ) { + len += sprintf (info->data + len, + "none"); + } else { + len += sprintf (info->data + len, + "%04X",devno); + } + len += sprintf (info->data + len, + "(none) at (%3d:%3d) is %7s: unknown", + temp->gendisk.major, + i << DASD_PARTN_BITS, + buffer); + } + if ( dasd_probeonly ) + len += sprintf(info->data + len,"(probeonly)"); + len += sprintf(info->data + len,"\n"); } + index += 1 << (MINORBITS - DASD_PARTN_BITS); } info->len = len; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif + spin_unlock_irqrestore(&discipline_lock,flags); return rc; } #define MIN(a,b) ((a)<(b)?(a):(b)) static ssize_t -dasd_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset) +dasd_generic_read (struct file *file, char *user_buf, size_t user_len, + loff_t * offset) { loff_t len; tempinfo_t *p_info = (tempinfo_t *) file->private_data; @@ -2894,85 +3565,68 @@ dasd_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * } static ssize_t -dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset) +dasd_devices_write (struct file *file, const char *user_buf, + size_t user_len, loff_t * offset) { char *buffer = vmalloc (user_len+1); int off = 0; char *temp; - int irq; - int j,target; - dasd_range_t *rptr, range; + dasd_range_t range; + int features = 0; if (buffer == NULL) return -ENOMEM; if (copy_from_user (buffer, user_buf, user_len)) { - vfree(buffer); + vfree (buffer); return -EFAULT; } buffer[user_len] = 0; - printk (KERN_INFO PRINTK_HEADER "Now executing %s\n", buffer); - if (strncmp ( buffer, "set ",4) && - strncmp ( buffer, "add ",4)){ - printk (KERN_WARNING PRINTK_HEADER - "/proc/dasd/devices: only 'set' and 'add' are supported verbs"); - return -EINVAL; - } - off += 4; - while (!isalnum(buffer[off])) off++; + printk (KERN_INFO PRINTK_HEADER "/proc/dasd/devices: '%s'\n", buffer); + if (strncmp (buffer, "set ", 4) && strncmp (buffer, "add ", 4)) { + printk (KERN_WARNING PRINTK_HEADER + "/proc/dasd/devices: only 'set' and 'add' are supported verbs\n"); + return -EINVAL; + } + off += 4; + while (buffer[off] && !isalnum (buffer[off])) + off++; if (!strncmp (buffer + off, "device", strlen ("device"))) { - off += strlen("device"); - while (!isalnum(buffer[off])) off++; - } + off += strlen ("device"); + while (buffer[off] && !isalnum (buffer[off])) + off++; + } if (!strncmp (buffer + off, "range=", strlen ("range="))) { - off += strlen("range="); - while (!isalnum(buffer[off])) off++; - } - temp = buffer+off; - range.from = dasd_strtoul (temp, &temp); - range.to = range.from; - if (*temp == '-') { - temp++; - range.to = dasd_strtoul (temp, &temp); - } - off = (long)temp - (long)buffer; - if ( !strncmp ( buffer, "add",strlen("add"))) { - rptr = dasd_add_range (range.from, range.to); - } else { - rptr = ⦥ - } - while (!isalnum(buffer[off])) off++; - printk (KERN_INFO PRINTK_HEADER - "varying device range %04X-%04X\n", rptr->from, rptr->to); - if ( !strncmp ( buffer, "add",strlen("add")) || - !strncmp ( buffer+off, "on",strlen("on")) ) { - target = DASD_DEVICE_LEVEL_ONLINE; - for (j = rptr->from; j <= rptr->to; j++) { - irq = get_irq_by_devno (j); - if (irq >= 0) { - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0); - } - } - printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); - { - static wait_queue_head_t wait_queue; - init_waitqueue_head (&wait_queue); - interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) ); + off += strlen ("range="); + while (buffer[off] && !isalnum (buffer[off])) + off++; + } + + temp = buffer + off; + range.from = dasd_strtoul (temp, &temp, &features); + range.to = range.from; + + if (*temp == '-') { + temp++; + range.to = dasd_strtoul (temp, &temp, &features); + } + + off = (long) temp - (long) buffer; + if (!strncmp (buffer, "add", strlen ("add"))) { + dasd_add_range (range.from, range.to, features); + dasd_enable_ranges (&range, NULL, 0); + } else { + while (buffer[off] && !isalnum (buffer[off])) + off++; + if (!strncmp (buffer + off, "on", strlen ("on"))) { + dasd_enable_ranges (&range, NULL, 0); + } else if (!strncmp (buffer + off, "off", strlen ("off"))) { + dasd_disable_ranges (&range, NULL, 0, 1); + } else { + printk (KERN_WARNING PRINTK_HEADER + "/proc/dasd/devices: parse error in '%s'", buffer); } - } else if ( !strncmp ( buffer+off, "off",strlen("off"))) { - target = DASD_DEVICE_LEVEL_UNKNOWN; - } else { - printk (KERN_WARNING PRINTK_HEADER - "/proc/dasd/devices: parse error in '%s'", buffer); - vfree (buffer); - return -EINVAL; - - } - for (j = rptr->from; j <= rptr->to; j++) { - irq = get_irq_by_devno (j); - if (irq >= 0) { - dasd_set_device_level (irq, target, NULL, 0); - } - } + } + vfree (buffer); return user_len; } @@ -2986,25 +3640,18 @@ dasd_devices_close (struct inode *inode, struct file *file) vfree (p_info->data); vfree (p_info); } -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif + MOD_DEC_USE_COUNT; return rc; } -static struct file_operations dasd_devices_file_ops = -{ - read:dasd_devices_read, /* read */ +static struct file_operations dasd_devices_file_ops = { + read:dasd_generic_read, /* read */ write:dasd_devices_write, /* write */ open:dasd_devices_open, /* open */ release:dasd_devices_close, /* close */ }; -static struct inode_operations dasd_devices_inode_ops = -{ -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - default_file_ops:&dasd_devices_file_ops /* file ops */ -#endif /* LINUX_IS_24 */ +static struct inode_operations dasd_devices_inode_ops = { }; static int @@ -3015,9 +3662,11 @@ dasd_statistics_open (struct inode *inode, struct file *file) tempinfo_t *info; int shift, i, help = 0; + MOD_INC_USE_COUNT; info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t)); if (info == NULL) { printk (KERN_WARNING "No memory available for data\n"); + MOD_DEC_USE_COUNT; return -ENOMEM; } else { file->private_data = (void *) info; @@ -3027,99 +3676,154 @@ dasd_statistics_open (struct inode *inode, struct file *file) printk (KERN_WARNING "No memory available for data\n"); vfree (info); file->private_data = NULL; + MOD_DEC_USE_COUNT; return -ENOMEM; } for (shift = 0, help = dasd_global_profile.dasd_io_reqs; - help > 8192; - help = help >> 1, shift++) ; - len = sprintf (info->data, "%ld dasd I/O requests\n", dasd_global_profile.dasd_io_reqs); - len += sprintf (info->data + len, "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n"); - len += sprintf (info->data + len, "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n"); + help > 8192; help = help >> 1, shift++) ; + len = + sprintf (info->data, "%d dasd I/O requests\n", + dasd_global_profile.dasd_io_reqs); + len += + sprintf (info->data + len, "with %d sectors(512B each)\n", + dasd_global_profile.dasd_io_sects); + len += + sprintf (info->data + len, + "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n"); + len += + sprintf (info->data + len, + "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n"); len += sprintf (info->data + len, "Histogram of sizes (512B secs)\n"); for (i = 0; i < 16; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_secs[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_secs[i] >> shift); } len += sprintf (info->data + len, "\n"); len += sprintf (info->data + len, "Histogram of I/O times\n"); for (i = 0; i < 16; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_times[i] >> shift); } len += sprintf (info->data + len, "\n"); for (; i < 32; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_times[i] >> shift); } len += sprintf (info->data + len, "\n"); - len += sprintf (info->data + len, "Histogram of I/O times per sector\n"); + len += + sprintf (info->data + len, "Histogram of I/O times per sector\n"); for (i = 0; i < 16; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_timps[i] >> shift); } len += sprintf (info->data + len, "\n"); for (; i < 32; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_timps[i] >> shift); } len += sprintf (info->data + len, "\n"); len += sprintf (info->data + len, "Histogram of I/O time till ssch\n"); for (i = 0; i < 16; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time1[i] >> shift); } len += sprintf (info->data + len, "\n"); for (; i < 32; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time1[i] >> shift); } len += sprintf (info->data + len, "\n"); - len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq\n"); + len += + sprintf (info->data + len, + "Histogram of I/O time between ssch and irq\n"); for (i = 0; i < 16; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time2[i] >> shift); } len += sprintf (info->data + len, "\n"); for (; i < 32; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time2[i] >> shift); } len += sprintf (info->data + len, "\n"); - len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq per sector\n"); + len += + sprintf (info->data + len, + "Histogram of I/O time between ssch and irq per sector\n"); for (i = 0; i < 16; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time2ps[i] >> shift); } len += sprintf (info->data + len, "\n"); for (; i < 32; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time2ps[i] >> shift); } len += sprintf (info->data + len, "\n"); - len += sprintf (info->data + len, "Histogram of I/O time between irq and end\n"); + len += + sprintf (info->data + len, + "Histogram of I/O time between irq and end\n"); for (i = 0; i < 16; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time3[i] >> shift); } len += sprintf (info->data + len, "\n"); for (; i < 32; i++) { - len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift); + len += + sprintf (info->data + len, "%4d ", + dasd_global_profile.dasd_io_time3[i] >> shift); } len += sprintf (info->data + len, "\n"); info->len = len; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif return rc; } -static struct file_operations dasd_statistics_file_ops = +static ssize_t +dasd_statistics_write (struct file *file, const char *user_buf, + size_t user_len, loff_t * offset) { - read:dasd_devices_read, /* read */ + char *buffer = vmalloc (user_len); + + if (buffer == NULL) + return -ENOMEM; + if (copy_from_user (buffer, user_buf, user_len)) { + vfree (buffer); + return -EFAULT; + } + buffer[user_len] = 0; + printk (KERN_INFO PRINTK_HEADER "/proc/dasd/statictics: '%s'\n", + buffer); + if (strncmp (buffer, "reset", 4)) { + memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t)); + } + return user_len; +} + +static struct file_operations dasd_statistics_file_ops = { + read:dasd_generic_read, /* read */ open:dasd_statistics_open, /* open */ + write:dasd_statistics_write, /* write */ release:dasd_devices_close, /* close */ }; -static struct inode_operations dasd_statistics_inode_ops = -{ -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - default_file_ops:&dasd_statistics_file_ops /* file ops */ -#endif /* LINUX_IS_24 */ +static struct inode_operations dasd_statistics_inode_ops = { }; int dasd_proc_init (void) { int rc = 0; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) dasd_proc_root_entry = proc_mkdir ("dasd", &proc_root); dasd_devices_entry = create_proc_entry ("devices", S_IFREG | S_IRUGO | S_IWUSR, @@ -3131,204 +3835,175 @@ dasd_proc_init (void) dasd_proc_root_entry); dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops; dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops; -#else - proc_register (&proc_root, &dasd_proc_root_entry); - dasd_devices_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC); - if (dasd_devices_entry) { - memset (dasd_devices_entry, 0, sizeof (struct proc_dir_entry)); - dasd_devices_entry->name = "devices"; - dasd_devices_entry->namelen = strlen ("devices"); - dasd_devices_entry->low_ino = 0; - dasd_devices_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR); - dasd_devices_entry->nlink = 1; - dasd_devices_entry->uid = 0; - dasd_devices_entry->gid = 0; - dasd_devices_entry->size = 0; - dasd_devices_entry->get_info = NULL; - dasd_devices_entry->ops = &dasd_devices_inode_ops; - proc_register (&dasd_proc_root_entry, dasd_devices_entry); - } - dasd_statistics_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC); - if (dasd_statistics_entry) { - memset (dasd_statistics_entry, 0, sizeof (struct proc_dir_entry)); - dasd_statistics_entry->name = "statistics"; - dasd_statistics_entry->namelen = strlen ("statistics"); - dasd_statistics_entry->low_ino = 0; - dasd_statistics_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR); - dasd_statistics_entry->nlink = 1; - dasd_statistics_entry->uid = 0; - dasd_statistics_entry->gid = 0; - dasd_statistics_entry->size = 0; - dasd_statistics_entry->get_info = NULL; - dasd_statistics_entry->ops = &dasd_statistics_inode_ops; - proc_register (&dasd_proc_root_entry, dasd_statistics_entry); - } -#endif /* LINUX_IS_24 */ return rc; } void dasd_proc_cleanup (void) { -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) remove_proc_entry ("devices", dasd_proc_root_entry); remove_proc_entry ("statistics", dasd_proc_root_entry); remove_proc_entry ("dasd", &proc_root); -#else - proc_unregister (&dasd_proc_root_entry, dasd_statistics_entry->low_ino); - kfree (dasd_statistics_entry); - proc_unregister (&dasd_proc_root_entry, dasd_devices_entry->low_ino); - kfree (dasd_devices_entry); - proc_unregister (&proc_root, dasd_proc_root_entry.low_ino); -#endif /* LINUX_IS_24 */ } +int +dasd_request_module ( void *name ) { + int rc = -ERESTARTSYS; + strcpy(current->comm, name); + daemonize(); + while ( current->fs->root == NULL ) { /* wait for root-FS */ + DECLARE_WAIT_QUEUE_HEAD(wait); + sleep_on_timeout(&wait,HZ); /* wait in steps of one second */ + } + while ( (rc=request_module(name)) != 0 ) { + DECLARE_WAIT_QUEUE_HEAD(wait); + printk ( KERN_INFO "request_module returned %d for %s\n",rc,(char*)name); + sleep_on_timeout(&wait,5* HZ); /* wait in steps of 5 seconds */ + } + return rc; +} + + /* SECTION: Initializing the driver */ int __init dasd_init (void) { int rc = 0; int irq; - int j; - major_info_t *major_info=NULL; + major_info_t *major_info = NULL; struct list_head *l; - dasd_range_t *range; printk (KERN_INFO PRINTK_HEADER "initializing...\n"); - dasd_debug_area = debug_register(DASD_NAME,0,2,3*sizeof(long)); - debug_register_view(dasd_debug_area,&debug_sprintf_view); - debug_register_view(dasd_debug_area,&debug_hex_ascii_view); - - if ( dasd_debug_area == NULL ) { - goto failed; - } - DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","ENTRY"); - dasd_devfs_handle = devfs_mk_dir(NULL,DASD_NAME,NULL); - if ( dasd_devfs_handle < 0 ) { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init,"%s","no devfs"); - goto failed; - } - list_for_each(l,&dasd_major_info[0].list) { - major_info=list_entry(l,major_info_t,list); - if ((rc = dasd_register_major (major_info)) > 0) { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "major %d: success",major_info->gendisk.major); - printk (KERN_INFO PRINTK_HEADER - "Registered successfully to major no %u\n", major_info->gendisk.major); + dasd_debug_area = debug_register (DASD_NAME, 0, 2, 4 * sizeof (long)); + debug_register_view (dasd_debug_area, &debug_sprintf_view); + debug_register_view (dasd_debug_area, &debug_hex_ascii_view); + + init_waitqueue_head (&dasd_init_waitq); + + if (dasd_debug_area == NULL) { + goto failed; + } + DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "ENTRY"); + dasd_devfs_handle = devfs_mk_dir (NULL, DASD_NAME, NULL); + if (dasd_devfs_handle < 0) { + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no devfs"); + goto failed; + } + list_for_each (l, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); + if ((rc = dasd_register_major (major_info)) > 0) { + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "major %d: success", + major_info->gendisk.major); + printk (KERN_INFO PRINTK_HEADER + "Registered successfully to major no %u\n", + major_info->gendisk.major); } else { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "major %d: failed",major_info->gendisk.major); + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "major %d: failed", + major_info->gendisk.major); printk (KERN_WARNING PRINTK_HEADER - "Couldn't register successfully to major no %d\n", major_info->gendisk.major); + "Couldn't register successfully to major no %d\n", + major_info->gendisk.major); /* revert registration of major infos */ - goto failed; + goto failed; } } #ifndef MODULE dasd_split_parm_string (dasd_parm_string); #endif /* ! MODULE */ dasd_parse (dasd); - dasd_init_emergency_req (); rc = dasd_proc_init (); if (rc) { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "%s","no proc-FS"); - goto failed; + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no proc-FS"); + goto failed; } genhd_dasd_name = dasd_device_name; - genhd_dasd_fillgeo = dasd_fillgeo; + if (dasd_autodetect) { /* update device range to all devices */ + for (irq = get_irq_first (); irq != -ENODEV; + irq = get_irq_next (irq)) { + int devno = get_devno_by_irq (irq); + int index = dasd_devindex_from_devno (devno); + if (index == -ENODEV) { /* not included in ranges */ + DASD_DRIVER_DEBUG_EVENT (2, dasd_init, + "add %04X to range", + devno); + dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES); + } + } + } + + if (MACHINE_IS_VM) { +#ifdef CONFIG_DASD_DIAG + rc = dasd_diag_init (); + if (rc == 0) { + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "DIAG discipline %s", + "success"); + printk (KERN_INFO PRINTK_HEADER + "Registered DIAG discipline successfully\n"); + } else { + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "DIAG discipline %s", + "failed"); + goto failed; + } +#endif /* CONFIG_DASD_DIAG */ +#if defined(CONFIG_DASD_DIAG_MODULE) && defined(CONFIG_DASD_AUTO_DIAG) + kernel_thread(dasd_request_module,"dasd_diag_mod",SIGCHLD); +#endif /* CONFIG_DASD_AUTO_DIAG */ + } #ifdef CONFIG_DASD_ECKD rc = dasd_eckd_init (); if (rc == 0) { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "ECKD discipline %s","success"); + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "ECKD discipline %s", "success"); printk (KERN_INFO PRINTK_HEADER "Registered ECKD discipline successfully\n"); } else { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "ECKD discipline %s","failed"); - goto failed; + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "ECKD discipline %s", "failed"); + goto failed; } -#endif /* CONFIG_DASD_ECKD */ +#endif /* CONFIG_DASD_ECKD */ +#if defined(CONFIG_DASD_ECKD_MODULE) && defined(CONFIG_DASD_AUTO_ECKD) + kernel_thread(dasd_request_module,"dasd_eckd_mod",SIGCHLD); +#endif /* CONFIG_DASD_AUTO_ECKD */ #ifdef CONFIG_DASD_FBA rc = dasd_fba_init (); if (rc == 0) { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "FBA discipline %s","success"); + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "FBA discipline %s", "success"); printk (KERN_INFO PRINTK_HEADER "Registered FBA discipline successfully\n"); } else { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "FBA discipline %s","failed"); - goto failed; - } -#endif /* CONFIG_DASD_FBA */ -#ifdef CONFIG_DASD_DIAG - if (MACHINE_IS_VM) { - rc = dasd_diag_init (); - if (rc == 0) { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "DIAG discipline %s","success"); - printk (KERN_INFO PRINTK_HEADER - "Registered DIAG discipline successfully\n"); - } else { - DASD_DRIVER_DEBUG_EVENT(1,dasd_init, - "DIAG discipline %s","failed"); - goto failed; - } + DASD_DRIVER_DEBUG_EVENT (1, dasd_init, + "FBA discipline %s", "failed"); + goto failed; } -#endif /* CONFIG_DASD_DIAG */ - rc = 0; - if (dasd_autodetect) { /* update device range to all devices */ - for (irq = get_irq_first (); irq != -ENODEV; - irq = get_irq_next (irq)) { - int devno = get_devno_by_irq (irq); - int index = dasd_devindex_from_devno (devno); - if (index == -ENODEV) { /* not included in ranges */ - DASD_DRIVER_DEBUG_EVENT(2,dasd_init, - "add %04X to range", - devno); - dasd_add_range (devno, 0); - } +#endif /* CONFIG_DASD_FBA */ +#if defined(CONFIG_DASD_FBA_MODULE) && defined(CONFIG_DASD_AUTO_FBA) + kernel_thread(dasd_request_module,"dasd_fba_mod",SIGCHLD); +#endif /* CONFIG_DASD_AUTO_FBA */ + { + char **disc=dasd_disciplines; + while (*disc) { + kernel_thread(dasd_request_module,*disc,SIGCHLD); + disc++; } } - for (range = dasd_range_head; range; range = range->next) { - for (j = range->from; j <= range->to; j++) { - irq = get_irq_by_devno (j); - if (irq >= 0) - DASD_DRIVER_DEBUG_EVENT(2,dasd_init, - "1st step in initialization irq 0x%x",irq); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, - NULL, 0); - } - } - printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); - { - static wait_queue_head_t wait_queue; - init_waitqueue_head (&wait_queue); - interruptible_sleep_on_timeout (&wait_queue, - (5 * HZ) ); - } - for (range = dasd_range_head; range; range = range->next) { - for (j = range->from; j <= range->to; j++) { - irq = get_irq_by_devno (j); - if (irq >= 0) { - DASD_DRIVER_DEBUG_EVENT(2,dasd_init, - "2nd step in initialization irq 0x%x",irq); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, - NULL, 0); - } - } - } - goto out; - failed: - printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n"); - cleanup_dasd(); - out: - DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE"); + + rc = 0; + goto out; + failed: + printk (KERN_INFO PRINTK_HEADER + "initialization not performed due to errors\n"); + cleanup_dasd (); + out: + DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "LEAVE"); printk (KERN_INFO PRINTK_HEADER "initialization finished\n"); return rc; } @@ -3336,95 +4011,78 @@ dasd_init (void) static void cleanup_dasd (void) { - int i,j,rc; - int irq; - major_info_t *major_info=NULL; - struct list_head *l; - dasd_range_t *range, *next; + int i,rc=0; + major_info_t *major_info = NULL; + struct list_head *l,*n; + dasd_range_t *range; printk (KERN_INFO PRINTK_HEADER "shutting down\n"); DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY"); - for (range = dasd_range_head; range; range = range->next) { - for (j = range->from; j <= range->to; j++) { - irq = get_irq_by_devno (j); - if (irq >= 0) { - DASD_DRIVER_DEBUG_EVENT(2,"cleanup_dasd", - "shutdown irq 0x%x",irq); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, - NULL, 0); - } - } - } + dasd_disable_ranges (&dasd_range_head, NULL, 1, 1); + if (MACHINE_IS_VM) { #ifdef CONFIG_DASD_DIAG - if (MACHINE_IS_VM) { - dasd_diag_cleanup (); - DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", - "DIAG discipline %s","success"); + dasd_diag_cleanup (); + DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd", + "DIAG discipline %s", "success"); printk (KERN_INFO PRINTK_HEADER - "De-Registered DIAG discipline successfully\n"); + "De-Registered DIAG discipline successfully\n"); +#endif /* CONFIG_DASD_ECKD_BUILTIN */ } -#endif /* CONFIG_DASD_DIAG */ #ifdef CONFIG_DASD_FBA dasd_fba_cleanup (); - DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", - "FBA discipline %s","success"); - printk (KERN_INFO PRINTK_HEADER - "De-Registered FBA discipline successfully\n"); -#endif /* CONFIG_DASD_FBA */ + DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd", + "FBA discipline %s", "success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered FBA discipline successfully\n"); +#endif /* CONFIG_DASD_ECKD_BUILTIN */ #ifdef CONFIG_DASD_ECKD dasd_eckd_cleanup (); - DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", - "ECKD discipline %s","success"); - printk (KERN_INFO PRINTK_HEADER - "De-Registered ECKD discipline successfully\n"); -#endif /* CONFIG_DASD_ECKD */ + DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd", + "ECKD discipline %s", "success"); + printk (KERN_INFO PRINTK_HEADER + "De-Registered ECKD discipline successfully\n"); +#endif /* CONFIG_DASD_ECKD_BUILTIN */ dasd_proc_cleanup (); - dasd_cleanup_emergency_req (); - - list_for_each(l,&dasd_major_info[0].list) { - major_info=list_entry(l,major_info_t,list); + + list_for_each_safe (l, n, &dasd_major_info[0].list) { + major_info = list_entry (l, major_info_t, list); for (i = 0; i < DASD_PER_MAJOR; i++) { kfree (major_info->dasd_device[i]); } - if ((major_info -> flags & DASD_MAJOR_INFO_REGISTERED) && + if ((major_info->flags & DASD_MAJOR_INFO_REGISTERED) && (rc = dasd_unregister_major (major_info)) == 0) { - DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", - "major %d: success",major_info->gendisk.major); + DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd", + "major %d: success", + major_info->gendisk.major); printk (KERN_INFO PRINTK_HEADER - "Unregistered successfully from major no %u\n", major_info->gendisk.major); + "Unregistered successfully from major no %u\n", + major_info->gendisk.major); } else { - DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd", - "major %d: failed",major_info->gendisk.major); + DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd", + "major %d: failed", + major_info->gendisk.major); printk (KERN_WARNING PRINTK_HEADER - "Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc); - } - } - + "Couldn't unregister successfully from major no %d rc = %d\n", + major_info->gendisk.major, rc); + } + } + list_for_each_safe (l, n, &dasd_range_head.list) { + range = list_entry (l, dasd_range_t, list); + dasd_remove_range(range); + } - range = dasd_range_head; - while (range) { - next = range->next; - dasd_remove_range (range); - if (next == NULL) - break; - else - range = next; - } - dasd_range_head = NULL; - #ifndef MODULE - for( j = 0; j < 256; j++ ) - if ( dasd[j] ) { - kfree(dasd[j]); - dasd[j] = NULL; + for( i = 0; i < 256; i++ ) + if ( dasd[i] ) { + kfree(dasd[i]); + dasd[i] = NULL; } #endif /* MODULE */ if (dasd_devfs_handle) devfs_unregister(dasd_devfs_handle); if (dasd_debug_area != NULL ) debug_unregister(dasd_debug_area); - printk (KERN_INFO PRINTK_HEADER "shutdown completed\n"); DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE"); } @@ -3434,7 +4092,7 @@ int init_module (void) { int rc = 0; - return dasd_init (); + rc = dasd_init (); return rc; } @@ -3453,7 +4111,7 @@ cleanup_module (void) * of the file. * --------------------------------------------------------------------------- * Local variables: - * c-indent-level: 4 + * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c index 55581f607d45..a81fa2f8abfb 100644 --- a/drivers/s390/block/dasd_3370_erp.c +++ b/drivers/s390/block/dasd_3370_erp.c @@ -6,8 +6,9 @@ */ #include <asm/ccwcache.h> -#include <asm/dasd.h> +#include "dasd_int.h" +#include "dasd_3370_erp.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER #define PRINTK_HEADER "dasd_erp(3370)" @@ -29,7 +30,7 @@ * dasd_era_fatal for all fatal (unrecoverable errors) * dasd_era_recover for all others. */ -dasd_era_t +dasd_era_t dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat) { char *sense = stat->ii.sense.data; @@ -37,7 +38,7 @@ dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat) /* check for successful execution first */ if (stat->cstat == 0x00 && stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; + return dasd_era_none; if (sense[0] & 0x80) { /* CMD reject */ return dasd_era_fatal; } diff --git a/drivers/s390/block/dasd_3370_erp.h b/drivers/s390/block/dasd_3370_erp.h new file mode 100644 index 000000000000..3b5639293ee9 --- /dev/null +++ b/drivers/s390/block/dasd_3370_erp.h @@ -0,0 +1,15 @@ +/* + * File...........: linux/drivers/s390/block/dasd_3370_erp.h + * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_3370_ERP_H +#define DASD_3370_ERP_H + +dasd_era_t dasd_3370_erp_examine (ccw_req_t *, devstat_t *); + +#endif /* DASD_3990_ERP_H */ diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index e4db50d3f354..c589c022c56f 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -4,13 +4,17 @@ * Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 + * + * History of changes: + * 05/14/01 fixed PL030160GTO (BUG() in erp_action_5) */ #include <asm/ccwcache.h> #include <asm/idals.h> -#include <asm/dasd.h> #include <asm/s390io.h> #include <linux/timer.h> + +#include "dasd_int.h" #include "dasd_eckd.h" #include "dasd_3990_erp.h" @@ -24,7 +28,6 @@ * SECTION DEBUG ROUTINES ***************************************************************************** */ -#ifdef ERP_DEBUG void log_erp_chain (ccw_req_t *cqr, int caller, @@ -34,104 +37,100 @@ log_erp_chain (ccw_req_t *cqr, ccw_req_t *loop_cqr = cqr; dasd_device_t *device = cqr->device; - char *page = (char *)get_free_page(GFP_ATOMIC); - int len = 0; int i; char *nl, *end_cqr, *begin, *end; + + /* dump sense data */ + if (device->discipline && + device->discipline->dump_sense ) { - if ( page == NULL ) { - printk (KERN_WARNING PRINTK_HEADER - "No memory to dump ERP chain\n"); - return; - } - + device->discipline->dump_sense (device, + cqr); + } + + /* log the channel program */ while (loop_cqr != NULL) { - memset (page, 0, 4096); - len = 0; - - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "device %04X on irq %d: (%s) ERP chain report for req: %p\n", - device->devinfo.devno, - device->devinfo.irq, - caller == 0 ? "EXAMINE" : "ACTION", - loop_cqr); + DASD_MESSAGE (KERN_ERR, device, + "(%s) ERP chain report for req: %p\n", + caller == 0 ? "EXAMINE" : "ACTION", + loop_cqr); nl = (char *) loop_cqr; end_cqr = nl + sizeof (ccw_req_t); - + while (nl < end_cqr) { - - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", - nl, - nl[0], nl[1], nl[2], nl[3], - nl[4], nl[5], nl[6], nl[7], - nl[8], nl[9], nl[10], nl[11], - nl[12], nl[13], nl[14], nl[15]); + + DASD_MESSAGE (KERN_ERR, device, + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); nl +=16; } nl = (char *) loop_cqr->cpaddr; + + if (loop_cqr->cplength > 40) { /* log only parts of the CP */ - if (loop_cqr->cplength > 40 ) { /* log only parts of the CP */ - - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "Start of channel program:\n"); - + DASD_MESSAGE (KERN_ERR, device, "%s", + "Start of channel program:\n"); + for (i = 0; i < 20; i += 2) { - - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", - nl, - nl[0], nl[1], nl[2], nl[3], - nl[4], nl[5], nl[6], nl[7], - nl[8], nl[9], nl[10], nl[11], - nl[12], nl[13], nl[14], nl[15]); + + DASD_MESSAGE (KERN_ERR, device, + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); nl += 16; } - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "End of channel program:\n"); + DASD_MESSAGE (KERN_ERR, device, "%s", + "End of channel program:\n"); nl = (char *) loop_cqr->cpaddr; nl += ((loop_cqr->cplength - 10) * 8); for (i = 0; i < 20; i += 2) { - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", - nl, - nl[0], nl[1], nl[2], nl[3], - nl[4], nl[5], nl[6], nl[7], - nl[8], nl[9], nl[10], nl[11], - nl[12], nl[13], nl[14], nl[15]); + DASD_MESSAGE (KERN_ERR, device, + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); nl += 16; } } else { /* log the whole CP */ - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "Channel program (complete):\n"); + DASD_MESSAGE (KERN_ERR, device, "%s", + "Channel program (complete):\n"); for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", - nl, - nl[0], nl[1], nl[2], nl[3], - nl[4], nl[5], nl[6], nl[7], - nl[8], nl[9], nl[10], nl[11], - nl[12], nl[13], nl[14], nl[15]); + DASD_MESSAGE (KERN_ERR, device, + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); nl += 16; } @@ -140,51 +139,47 @@ log_erp_chain (ccw_req_t *cqr, /* log bytes arround failed CCW if not already done */ begin = (char *) loop_cqr->cpaddr; end = begin + ((loop_cqr->cplength+4) * 8); - nl = (void *)cpa; + nl = (void *)(long)cpa; if (loop_cqr == cqr) { /* log only once */ - if ((loop_cqr->cplength > 40) || /* not whole CP was logged or */ - ((nl < begin ) && /* CCW is outside logged CP */ - (nl > end ) ) ) { + /* if not whole CP logged OR CCW outside logged CP */ + if ((loop_cqr->cplength > 40) || + ((nl < begin ) && + (nl > end ) ) ) { - nl -= 10*8; /* start some bytes before */ + nl -= 10*8; /* start some bytes before */ - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "Failed CCW (%p) (area):\n", - (void *)cpa); + DASD_MESSAGE (KERN_ERR, device, + "Failed CCW (%p) (area):\n", + (void *)(long)cpa); for (i = 0; i < 20; i += 2) { - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", - nl, - nl[0], nl[1], nl[2], nl[3], - nl[4], nl[5], nl[6], nl[7], - nl[8], nl[9], nl[10], nl[11], - nl[12], nl[13], nl[14], nl[15]); + DASD_MESSAGE (KERN_ERR, device, + "%p: %02x%02x%02x%02x %02x%02x%02x%02x " + "%02x%02x%02x%02x %02x%02x%02x%02x\n", + nl, + nl[0], nl[1], nl[2], nl[3], + nl[4], nl[5], nl[6], nl[7], + nl[8], nl[9], nl[10], nl[11], + nl[12], nl[13], nl[14], nl[15]); nl += 16; } } else { - len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER - "Failed CCW (%p) already logged\n", - (void *)cpa); + DASD_MESSAGE (KERN_ERR, device, + "Failed CCW (%p) already logged\n", + (void *)(long)cpa); } } - - printk ("%s", page); + loop_cqr = loop_cqr->refers; } - free_page ((unsigned long) page); - } /* end log_erp_chain */ -#endif /* ERP_DEBUG */ - /* ***************************************************************************** @@ -211,32 +206,46 @@ log_erp_chain (ccw_req_t *cqr, * dasd_era_recover for all others. */ dasd_era_t -dasd_3990_erp_examine_24 (char *sense) +dasd_3990_erp_examine_24 (ccw_req_t *cqr, + char *sense) { - /* check for 'Command Recejct' which is always a fatal error */ - if (sense[0] & SNS0_CMD_REJECT) { - if (sense[2] & SNS2_ENV_DATA_PRESENT) { - return dasd_era_recover; - } else { - return dasd_era_fatal; - } + dasd_device_t *device = cqr->device; + + /* check for 'Command Reject' */ + if (( sense[0] & SNS0_CMD_REJECT ) && + (!(sense[2] & SNS2_ENV_DATA_PRESENT)) ) { + + DASD_MESSAGE (KERN_ERR, device, "%s", + "EXAMINE 24: Command Reject detected - " + "fatal error"); + + return dasd_era_fatal; } - /* check for 'Invalid Track Format' */ - if (sense[1] & SNS1_INV_TRACK_FORMAT) { - if (sense[2] & SNS2_ENV_DATA_PRESENT) { - return dasd_era_recover; - } else { - return dasd_era_fatal; - } + + /* check for 'Invalid Track Format' */ + if (( sense[1] & SNS1_INV_TRACK_FORMAT ) && + (!(sense[2] & SNS2_ENV_DATA_PRESENT)) ) { + + DASD_MESSAGE (KERN_ERR, device, "%s", + "EXAMINE 24: Invalid Track Format detected " + "- fatal error"); + + return dasd_era_fatal; } - /* check for 'No Record Found' */ + + /* check for 'No Record Found' */ if (sense[1] & SNS1_NO_REC_FOUND) { - return dasd_era_fatal; + + DASD_MESSAGE (KERN_ERR, device, "%s", + "EXAMINE 24: No Record Found detected " + "- fatal error"); + + return dasd_era_fatal; } - /* return recoverable for all others */ - return dasd_era_recover; + /* return recoverable for all others */ + return dasd_era_recover; } /* END dasd_3990_erp_examine_24 */ /* @@ -253,19 +262,27 @@ dasd_3990_erp_examine_24 (char *sense) * dasd_era_recover for recoverable others. */ dasd_era_t -dasd_3990_erp_examine_32 (char *sense) +dasd_3990_erp_examine_32 (ccw_req_t *cqr, + char *sense) { + dasd_device_t *device = cqr->device; + switch (sense[25]) { case 0x00: return dasd_era_none; + case 0x01: + DASD_MESSAGE (KERN_ERR, device, "%s", + "EXAMINE 32: fatal error"); return dasd_era_fatal; + default: + return dasd_era_recover; } -} /* end dasd_3990_erp_examine_32 */ +} /* end dasd_3990_erp_examine_32 */ /* * DASD_3990_ERP_EXAMINE @@ -292,31 +309,30 @@ dasd_3990_erp_examine (ccw_req_t *cqr, dasd_era_t era = dasd_era_recover; /* check for successful execution first */ - if (stat->cstat == 0x00 && - stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) + if (stat->cstat == 0x00 && + stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) ) return dasd_era_none; /* distinguish between 24 and 32 byte sense data */ if (sense[27] & DASD_SENSE_BIT_0) { - /* examine the 24 byte sense data */ - era = dasd_3990_erp_examine_24 (sense); + era = dasd_3990_erp_examine_24 (cqr, + sense); } else { - /* examine the 32 byte sense data */ - era = dasd_3990_erp_examine_32 (sense); + era = dasd_3990_erp_examine_32 (cqr, + sense); - } /* end distinguish between 24 and 32 byte sense data */ + } -#ifdef ERP_DEBUG + /* log the erp chain if fatal error occurred */ if (era == dasd_era_fatal) { log_erp_chain (cqr, 0, stat->cpa); } -#endif /* ERP_DEBUG */ return era; @@ -334,6 +350,37 @@ dasd_3990_erp_examine (ccw_req_t *cqr, */ /* + * DASD_3990_ERP_CLEANUP + * + * DESCRIPTION + * Removes the already build but not neccessary ERP request and sets + * the status of the original cqr / erp to the given (final) status + * + * PARAMETER + * erp request to be blocked + * final_status either CQR_STATUS_DONE or CQR_STATUS_FAILED + * + * RETURN VALUES + * cqr original cqr + */ +ccw_req_t * +dasd_3990_erp_cleanup (ccw_req_t *erp, + char final_status) +{ + + ccw_req_t *cqr = erp->refers; + + dasd_free_request (erp, erp->device); + + check_then_set (&cqr->status, + CQR_STATUS_ERROR, + final_status); + + return cqr; + +} /* end dasd_3990_erp_cleanup */ + +/* * DASD_3990_ERP_BLOCK_QUEUE * * DESCRIPTION @@ -365,8 +412,9 @@ dasd_3990_erp_block_queue (ccw_req_t *erp, /* restart queue after some time */ device->timer.function = dasd_3990_erp_restart_queue; - device->timer.data = (unsigned long) erp; - device->timer.expires = jiffies + (expires * HZ); + device->timer.data = (unsigned long) erp; + device->timer.expires = jiffies + (expires * HZ); + add_timer(&device->timer); } /* end dasd_3990_erp_block_queue */ @@ -390,6 +438,7 @@ dasd_3990_erp_block_queue (ccw_req_t *erp, void dasd_3990_erp_restart_queue (unsigned long erp) { + ccw_req_t *cqr = (void *) erp; dasd_device_t *device = cqr->device; unsigned long flags; @@ -399,10 +448,9 @@ dasd_3990_erp_restart_queue (unsigned long erp) flags); /* 'restart' the device queue */ - if (cqr->status == CQR_STATUS_PENDING){ + if (cqr->status == CQR_STATUS_PENDING) { - DASD_MESSAGE (KERN_INFO, device, - "%s", + DASD_MESSAGE (KERN_INFO, device, "%s", "request queue restarted by MIH"); check_then_set (&cqr->status, @@ -414,11 +462,10 @@ dasd_3990_erp_restart_queue (unsigned long erp) s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); - dasd_schedule_bh(device); + dasd_schedule_bh (device); } /* end dasd_3990_erp_restart_queue */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERP_INT_REQ * @@ -434,27 +481,31 @@ dasd_3990_erp_restart_queue (unsigned long erp) ccw_req_t * dasd_3990_erp_int_req (ccw_req_t *erp) { + dasd_device_t *device = erp->device; /* first time set initial retry counter and erp_function */ + /* and retry once without blocking queue */ + /* (this enables easier enqueing of the cqr) */ if (erp->function != dasd_3990_erp_int_req) { + erp->retries = 256; erp->function = dasd_3990_erp_int_req; - } - /* issue a message and wait for 'device ready' interrupt */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "is offline or not installed - " - "INTERVENTION REQUIRED!!\n"); + } else { - dasd_3990_erp_block_queue (erp, - 60); + /* issue a message and wait for 'device ready' interrupt */ + DASD_MESSAGE (KERN_ERR, device, "%s", + "is offline or not installed - " + "INTERVENTION REQUIRED!!"); + + dasd_3990_erp_block_queue (erp, + 60); + } return erp; } /* end dasd_3990_erp_int_req */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_ALTERNATE_PATH @@ -478,22 +529,17 @@ dasd_3990_erp_alternate_path (ccw_req_t *erp) dasd_device_t *device = erp->device; int irq = device->devinfo.irq; - /* dissable current channel path - this causes the use of an other - channel path if there is one.. */ - - DASD_MESSAGE (KERN_WARNING, device, - "disable lpu %x", - erp->dstat->lpum); - /* try alternate valid path */ erp->lpm &= ~(erp->dstat->lpum); erp->options |= DOIO_VALID_LPM; /* use LPM for DO_IO */ if ((erp->lpm & ioinfo[irq]->opm) != 0x00) { - DASD_MESSAGE (KERN_WARNING, device, - "try alternate lpm %x", - erp->lpm); + DASD_MESSAGE (KERN_DEBUG, device, + "try alternate lpm=%x (lpum=%x / opm=%x)", + erp->lpm, + erp->dstat->lpum, + ioinfo[irq]->opm); /* reset status to queued to handle the request again... */ check_then_set (&erp->status, @@ -504,10 +550,11 @@ dasd_3990_erp_alternate_path (ccw_req_t *erp) } else { - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "No alternate channel path left -> " - "permanent error"); + DASD_MESSAGE (KERN_ERR, device, + "No alternate channel path left (lpum=%x / " + "opm=%x) -> permanent error", + erp->dstat->lpum, + ioinfo[irq]->opm); /* post request with permanent error */ check_then_set (&erp->status, @@ -518,7 +565,6 @@ dasd_3990_erp_alternate_path (ccw_req_t *erp) } /* end dasd_3990_erp_alternate_path */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERP_DCTL * @@ -527,7 +573,7 @@ dasd_3990_erp_alternate_path (ccw_req_t *erp) * Inhibit Write subcommand (0x20) and the given modifier. * * PARAMETER - * erp pointer to the current ERP + * erp pointer to the current (failed) ERP * modifier subcommand modifier * * RETURN VALUES @@ -538,14 +584,25 @@ ccw_req_t * dasd_3990_erp_DCTL (ccw_req_t *erp, char modifier) { - DCTL_data_t *DCTL_data; - ccw1_t *ccw; - ccw_req_t *dctl_cqr = dasd_alloc_request ((char *) &erp->magic, - 1, - sizeof(DCTL_data_t)); + + dasd_device_t *device = erp->device; + DCTL_data_t *DCTL_data; + ccw1_t *ccw; + ccw_req_t *dctl_cqr = dasd_alloc_request ((char *) &erp->magic, + 1, + sizeof(DCTL_data_t), + erp->device); - if (dctl_cqr == NULL) { - BUG(); + if (!dctl_cqr) { + + DASD_MESSAGE (KERN_ERR, device, "%s", + "Unable to allocate DCTL-CQR"); + + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return erp; } DCTL_data = dctl_cqr->data; @@ -557,15 +614,24 @@ dasd_3990_erp_DCTL (ccw_req_t *erp, memset (ccw, 0, sizeof (ccw1_t)); ccw->cmd_code = CCW_CMD_DCTL; ccw->count = 4; - set_normalized_cda(ccw, __pa (DCTL_data)); + if (dasd_set_normalized_cda(ccw, + __pa (DCTL_data), dctl_cqr, erp->device)) { + dasd_free_request (dctl_cqr, erp->device); + DASD_MESSAGE (KERN_ERR, device, "%s", + "Unable to allocate DCTL-CQR"); + check_then_set (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + return erp; + } dctl_cqr->function = dasd_3990_erp_DCTL; - dctl_cqr->refers = erp; - dctl_cqr->device = erp->device; - dctl_cqr->magic = erp->magic; - dctl_cqr->lpm = LPM_ANYPATH; - dctl_cqr->expires = 5 * TOD_MIN; - dctl_cqr->retries = 2; + dctl_cqr->refers = erp; + dctl_cqr->device = erp->device; + dctl_cqr->magic = erp->magic; + dctl_cqr->lpm = LPM_ANYPATH; + dctl_cqr->expires = 5 * TOD_MIN; + dctl_cqr->retries = 2; asm volatile ("STCK %0":"=m" (dctl_cqr->buildclk)); dctl_cqr->status = CQR_STATUS_FILLED; @@ -573,7 +639,6 @@ dasd_3990_erp_DCTL (ccw_req_t *erp, return dctl_cqr; } /* end dasd_3990_erp_DCTL */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_ACTION_1 @@ -595,6 +660,7 @@ dasd_3990_erp_DCTL (ccw_req_t *erp, ccw_req_t * dasd_3990_erp_action_1 (ccw_req_t *erp) { + erp->function = dasd_3990_erp_action_1; dasd_3990_erp_alternate_path (erp); @@ -624,21 +690,22 @@ ccw_req_t * dasd_3990_erp_action_4 (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; /* first time set initial retry counter and erp_function */ /* and retry once without waiting for state change pending */ /* interrupt (this enables easier enqueing of the cqr) */ if (erp->function != dasd_3990_erp_action_4) { - erp->retries = 255; + + erp->retries = 256; erp->function = dasd_3990_erp_action_4; } else { if (sense[25] & 0x1D) { /* state change pending */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_INFO, device, "%s", "waiting for state change pending " "int"); @@ -646,11 +713,8 @@ dasd_3990_erp_action_4 (ccw_req_t *erp, 30); } else { + /* no state change pending - retry */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "no state change pending - retry"); - check_then_set (&erp->status, CQR_STATUS_ERROR, CQR_STATUS_QUEUED); @@ -667,12 +731,12 @@ dasd_3990_erp_action_4 (ccw_req_t *erp, ***************************************************************************** */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERP_ACTION_5 * * DESCRIPTION * Setup ERP to do the ERP action 5 (see Reference manual). + * NOTE: Further handling is done in xxx_further_erp after the retries. * * PARAMETER * erp pointer to the current ERP @@ -684,16 +748,11 @@ dasd_3990_erp_action_4 (ccw_req_t *erp, ccw_req_t * dasd_3990_erp_action_5 (ccw_req_t *erp) { + /* first of all retry */ erp->retries = 10; erp->function = dasd_3990_erp_action_5; - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); - - /* further handling is done in xxx_further_erp after the retries */ - return erp; } /* end dasd_3990_erp_action_5 */ @@ -713,15 +772,17 @@ dasd_3990_erp_action_5 (ccw_req_t *erp) * void */ void -dasd_3990_handle_env_data (char *sense) +dasd_3990_handle_env_data (ccw_req_t *erp, + char *sense) { - /* check bytes 7-23 for further information */ - char msg_format = (sense[7] & 0xF0); - char msg_no = (sense[7] & 0x0F); + dasd_device_t *device = erp->device; + char msg_format = (sense[7] & 0xF0); + char msg_no = (sense[7] & 0x0F); + switch (msg_format) { - case 0x00: /* Format 0 - Program or System Checks */ + case 0x00: /* Format 0 - Program or System Checks */ if (sense[1] & 0x10) { /* check message to operator bit */ @@ -729,579 +790,595 @@ dasd_3990_handle_env_data (char *sense) case 0x00: /* No Message */ break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Invalid Command\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Command"); break; case 0x02: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Invalid Command Sequence\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Command " + "Sequence"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - CCW Count less than " - "required\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - CCW Count less than " + "required"); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Invalid Parameter\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Parameter"); break; case 0x05: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Diagnostic of Sepecial " - "Command Violates File Mask\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Diagnostic of Sepecial" + " Command Violates File Mask"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Channel Returned with " - "Incorrect retry CCW\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Channel Returned with " + "Incorrect retry CCW"); break; case 0x08: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Reset Notification\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Reset Notification"); break; case 0x09: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Storage Path Restart\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Storage Path Restart"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Channel requested ... %02x\n", - sense[8]); + DASD_MESSAGE (KERN_WARNING, device, + "FORMAT 0 - Channel requested " + "... %02x", + sense[8]); break; case 0x0B: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Invalid Defective/Alternate " - "Track Pointer\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Defective/" + "Alternate Track Pointer"); break; case 0x0C: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - DPS Installation Check\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - DPS Installation " + "Check"); break; case 0x0E: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Command Invalid on Secondary " - "Address\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Command Invalid on " + "Secondary Address"); break; case 0x0F: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Status Not As Required: " - "reason %02x\n", - sense[8]); + DASD_MESSAGE (KERN_WARNING, device, + "FORMAT 0 - Status Not As " + "Required: reason %02x", + sense[8]); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Reseved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Reseved"); } } else { switch (msg_no) { case 0x00: /* No Message */ break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Device Error Source\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Device Error Source"); break; case 0x02: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Reserved"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Device Fenced - device = " - "%02x\n", - sense[4]); + DASD_MESSAGE (KERN_WARNING, device, + "FORMAT 0 - Device Fenced - " + "device = %02x", + sense[4]); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Data Pinned for Device\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Data Pinned for " + "Device"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 0 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 0 - Reserved"); } } break; - case 0x10: /* Format 1 - Device Equipment Checks */ + case 0x10: /* Format 1 - Device Equipment Checks */ switch (msg_no) { case 0x00: /* No Message */ break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Device Status 1 not as " - "expected\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Device Status 1 not as " + "expected"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Index missing\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Index missing"); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Interruption cannot be reset\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Interruption cannot be reset"); break; case 0x05: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Device did not respond to " - "selection\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Device did not respond to " + "selection"); break; case 0x06: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Device check-2 error or Set " - "Sector is not complete\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Device check-2 error or Set " + "Sector is not complete"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Head address does not compare\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Head address does not " + "compare"); break; case 0x08: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Device status 1 not valid\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Device status 1 not valid"); break; case 0x09: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Device not ready\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Device not ready"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Track physical address did " - "not compare\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Track physical address did " + "not compare"); break; case 0x0B: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Missing device address bit\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Missing device address bit"); break; case 0x0C: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Drive motor switch is off\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Drive motor switch is off"); break; case 0x0D: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Seek incomplete\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Seek incomplete"); break; case 0x0E: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Cylinder address did not " - "compare\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Cylinder address did not " + "compare"); break; case 0x0F: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Offset active cannot be reset\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Offset active cannot be " + "reset"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 1 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 1 - Reserved"); } break; - case 0x20: /* Format 2 - 3990 Equipment Checks */ + case 0x20: /* Format 2 - 3990 Equipment Checks */ switch (msg_no) { case 0x08: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 2 - 3990 check-2 error\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 2 - 3990 check-2 error"); break; case 0x0E: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 2 - Support facility errors\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 2 - Support facility errors"); break; case 0x0F: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 2 - Microcode detected error %02x\n", - sense[8]); + DASD_MESSAGE (KERN_WARNING, device, + "FORMAT 2 - Microcode detected error %02x", + sense[8]); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 2 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 2 - Reserved"); } break; - case 0x30: /* Format 3 - 3990 Control Checks */ + case 0x30: /* Format 3 - 3990 Control Checks */ switch (msg_no) { case 0x0F: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 3 - Allegiance terminated\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 3 - Allegiance terminated"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 3 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 3 - Reserved"); } break; - case 0x40: /* Format 4 - Data Checks */ + case 0x40: /* Format 4 - Data Checks */ switch (msg_no) { case 0x00: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Home address area error\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Home address area error"); break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Count area error\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Count area error"); break; case 0x02: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Key area error\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Key area error"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Data area error\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Data area error"); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No sync byte in home address area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in home address " + "area"); break; case 0x05: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No syn byte in count address area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in count address " + "area"); break; case 0x06: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No sync byte in key area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in key area"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No syn byte in data area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in data area"); break; case 0x08: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Home address area error; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Home address area error; " + "offset active"); break; case 0x09: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Count area error; offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Count area error; offset " + "active"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Key area error; offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Key area error; offset " + "active"); break; case 0x0B: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Data area error; offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Data area error; " + "offset active"); break; case 0x0C: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No sync byte in home address area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in home " + "address area; offset active"); break; case 0x0D: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No syn byte in count address area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No syn byte in count " + "address area; offset active"); break; case 0x0E: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No sync byte in key area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in key area; " + "offset active"); break; case 0x0F: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - No syn byte in data area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - No syn byte in data area; " + "offset active"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 4 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 4 - Reserved"); } break; - case 0x50: /* Format 5 - Data Check with displacement information */ + case 0x50: /* Format 5 - Data Check with displacement information */ switch (msg_no) { case 0x00: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the home address area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the " + "home address area"); break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the count area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the count area"); break; case 0x02: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the key area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the key area"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the data area\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the data area"); break; case 0x08: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the home address area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the " + "home address area; offset active"); break; case 0x09: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the count area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the count area; " + "offset active"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the key area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the key area; " + "offset active"); break; case 0x0B: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Data Check in the data area; " - "offset active\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the data area; " + "offset active"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 5 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 5 - Reserved"); } break; - case 0x60: /* Format 6 - Usage Statistics/Overrun Errors */ + case 0x60: /* Format 6 - Usage Statistics/Overrun Errors */ switch (msg_no) { case 0x00: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel A\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel A"); break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel B\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel B"); break; case 0x02: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel C\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel C"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel D\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel D"); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel E\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel E"); break; case 0x05: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel F\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel F"); break; case 0x06: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel G\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel G"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Overrun on channel H\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel H"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 6 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 6 - Reserved"); } break; - case 0x70: /* Format 7 - Device Connection Control Checks */ + case 0x70: /* Format 7 - Device Connection Control Checks */ switch (msg_no) { case 0x00: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - RCC initiated by a connection " - "check alert\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - RCC initiated by a connection " + "check alert"); break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - RCC 1 sequence not successful\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - RCC 1 sequence not " + "successful"); break; case 0x02: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - RCC 1 and RCC 2 sequences not " - "successful\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - RCC 1 and RCC 2 sequences not " + "successful"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Invalid tag-in during selection " - "sequence\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid tag-in during " + "selection sequence"); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - extra RCC required\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - extra RCC required"); break; case 0x05: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Invalid DCC selection response " - "or timeout\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid DCC selection " + "response or timeout"); break; case 0x06: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Missing end operation; device " - "transfer complete\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Missing end operation; device " + "transfer complete"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Missing end operation; device " - "transfer incomplete\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Missing end operation; device " + "transfer incomplete"); break; case 0x08: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Invalid tag-in for an immediate " - "command sequence\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid tag-in for an " + "immediate command sequence"); break; case 0x09: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Invalid tag-in for an extended " - "command sequence\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid tag-in for an " + "extended command sequence"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - 3990 microcode time out when " - "stopping selection\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - 3990 microcode time out when " + "stopping selection"); break; case 0x0B: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - No response to selection after " - "a poll interruption\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - No response to selection " + "after a poll interruption"); break; case 0x0C: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Permanent path error (DASD " - "controller not available)\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Permanent path error (DASD " + "controller not available)"); break; case 0x0D: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - DASD controller not available on " - "disconnected command chain\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - DASD controller not available" + " on disconnected command chain"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 7 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 7 - Reserved"); } break; - case 0x80: /* Format 8 - Additional Device Equipment Checks */ + case 0x80: /* Format 8 - Additional Device Equipment Checks */ switch (msg_no) { case 0x00: /* No Message */ case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - Error correction code hardware " - "fault\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - Error correction code " + "hardware fault"); break; case 0x03: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - Unexpected end operation response " - "code\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - Unexpected end operation " + "response code"); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - End operation with transfer count " - "not zero\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - End operation with transfer " + "count not zero"); break; case 0x05: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - End operation with transfer " - "count zero\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - End operation with transfer " + "count zero"); break; case 0x06: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - DPS checks after a system reset or " - "selective reset\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - DPS checks after a system " + "reset or selective reset"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - DPS cannot be filled\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - DPS cannot be filled"); break; case 0x08: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - Short busy time-out during device " - "selection\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - Short busy time-out during " + "device selection"); break; case 0x09: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - DASD controller failed to set or " - "reset the long busy latch\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - DASD controller failed to " + "set or reset the long busy latch"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - No interruption from device during " - "a command chain\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - No interruption from device " + "during a command chain"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 8 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 8 - Reserved"); } break; - case 0x90: /* Format 9 - Device Read, Write, and Seek Checks */ + case 0x90: /* Format 9 - Device Read, Write, and Seek Checks */ switch (msg_no) { case 0x00: break; /* No Message */ case 0x06: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 9 - Device check-2 error\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 9 - Device check-2 error"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 9 - Head address did not compare\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 9 - Head address did not compare"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 9 - Track physical address did not " - "compare while oriented\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 9 - Track physical address did " + "not compare while oriented"); break; case 0x0E: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 9 - Cylinder address did not compare\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 9 - Cylinder address did not " + "compare"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT 9 - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT 9 - Reserved"); } break; case 0xF0: /* Format F - Cache Storage Checks */ switch (msg_no) { case 0x00: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Operation Terminated\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Operation Terminated"); break; case 0x01: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Subsystem Processing Error\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Subsystem Processing Error"); break; case 0x02: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Cache or nonvolatile storage " - "equipment failure\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Cache or nonvolatile storage " + "equipment failure"); break; case 0x04: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Caching terminated\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Caching terminated"); break; case 0x06: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Cache fast write access not " - "authorized\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Cache fast write access not " + "authorized"); break; case 0x07: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Track format incorrect\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Track format incorrect"); break; case 0x09: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Caching reinitiated\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Caching reinitiated"); break; case 0x0A: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Nonvolatile storage terminated\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Nonvolatile storage " + "terminated"); break; case 0x0B: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Volume is suspended duplex\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Volume is suspended duplex"); break; case 0x0C: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Subsystem status connot be " - "determined\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Subsystem status connot be " + "determined"); break; case 0x0D: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - Caching status reset to default\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - Caching status reset to " + "default"); break; case 0x0E: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT F - DASD Fast Write inhibited\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT F - DASD Fast Write inhibited"); break; default: - printk (KERN_WARNING PRINTK_HEADER - "FORMAT D - Reserved\n"); + DASD_MESSAGE (KERN_WARNING, device, "%s", + "FORMAT D - Reserved"); } break; - default: /* unknown message format - should not happen */ + default: /* unknown message format - should not happen */ } /* end switch message format */ @@ -1324,38 +1401,29 @@ ccw_req_t * dasd_3990_erp_com_rej (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; - ccw_req_t *cqr = NULL; erp->function = dasd_3990_erp_com_rej; /* env data present (ACTION 10 - retry should work) */ if (sense[2] & SNS2_ENV_DATA_PRESENT) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Command Reject - environmental data present\n"); + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "Command Reject - environmental data present"); - dasd_3990_handle_env_data (sense); + dasd_3990_handle_env_data (erp, + sense); erp->retries = 5; } else { /* fatal error - set status to FAILED */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Command Reject - Fatal error\n"); - - cqr = erp->refers; - - dasd_free_request (erp); - - erp = cqr; - - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + DASD_MESSAGE (KERN_ERR, device, "%s", + "Command Reject - Fatal error"); + erp = dasd_3990_erp_cleanup (erp, + CQR_STATUS_FAILED); } return erp; @@ -1376,27 +1444,31 @@ dasd_3990_erp_com_rej (ccw_req_t *erp, ccw_req_t * dasd_3990_erp_bus_out (ccw_req_t *erp) { + dasd_device_t *device = erp->device; /* first time set initial retry counter and erp_function */ + /* and retry once without blocking queue */ + /* (this enables easier enqueing of the cqr) */ if (erp->function != dasd_3990_erp_bus_out) { erp->retries = 256; erp->function = dasd_3990_erp_bus_out; - } - - /* issue a message and wait for 'device ready' interrupt */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "bus out parity error or BOPC requested by channel\n"); + } else { - dasd_3990_erp_block_queue (erp, - 60); + /* issue a message and wait for 'device ready' interrupt */ + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "bus out parity error or BOPC requested by " + "channel"); + + dasd_3990_erp_block_queue (erp, + 60); + + } return erp; } /* end dasd_3990_erp_bus_out */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_EQUIP_CHECK @@ -1413,60 +1485,51 @@ ccw_req_t * dasd_3990_erp_equip_check (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; erp->function = dasd_3990_erp_equip_check; -#ifdef ERP_FULL_ERP if (sense[1] & SNS1_WRITE_INHIBITED) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Write inhibited path encountered"); /* vary path offline */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_ERR, device, "%s", "Path should be varied off-line. " - "This is not implemented yet \n - please report to " - "linux390@de.ibm.com"); + "This is not implemented yet \n - please report " + "to linux390@de.ibm.com"); erp = dasd_3990_erp_action_1 (erp); - } else -#endif /* ERP_FULL_ERP */ - if (sense[2] & SNS2_ENV_DATA_PRESENT) { - - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Equipment Check - " - "environmental data present"); -#ifdef ERP_FULL_ERP - dasd_3990_handle_env_data (sense); -#endif /* ERP_FULL_ERP */ - - erp = dasd_3990_erp_action_4 (erp, - sense); - -#ifdef ERP_FULL_ERP - } else if (sense[1] & SNS1_PERM_ERR) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Equipment Check - retry exhausted or " - "undesirable\n"); - - erp = dasd_3990_erp_action_1 (erp); - - } else { - /* all other equipment checks - Action 5 */ - /* rest is done when retries == 0 */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Equipment check or processing error\n"); - - erp = dasd_3990_erp_action_5 (erp); -#endif /* ERP_FULL_ERP */ - } + } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "Equipment Check - " + "environmental data present"); + + dasd_3990_handle_env_data (erp, + sense); + + erp = dasd_3990_erp_action_4 (erp, + sense); + + } else if (sense[1] & SNS1_PERM_ERR) { + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "Equipment Check - retry exhausted or " + "undesirable"); + + erp = dasd_3990_erp_action_1 (erp); + + } else { + /* all other equipment checks - Action 5 */ + /* rest is done when retries == 0 */ + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "Equipment check or processing error"); + + erp = dasd_3990_erp_action_5 (erp); + } return erp; @@ -1487,18 +1550,17 @@ ccw_req_t * dasd_3990_erp_data_check (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; erp->function = dasd_3990_erp_data_check; -#ifdef ERP_FULL_ERP if (sense[2] & SNS2_CORRECTABLE) { /* correctable data check */ /* issue message that the data has been corrected */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_EMERG, device, "%s", "Data recovered during retry with PCI " - "fetch mode active\n"); + "fetch mode active"); /* not possible to handle this situation in Linux */ panic("No way to inform appliction about the possibly " @@ -1506,8 +1568,7 @@ dasd_3990_erp_data_check (ccw_req_t *erp, } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Uncorrectable data check recovered secondary " "addr of duplex pair"); @@ -1516,41 +1577,25 @@ dasd_3990_erp_data_check (ccw_req_t *erp, } else if (sense[1] & SNS1_PERM_ERR) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Uncorrectable data check with internal " - "retry exhausted\n"); + "retry exhausted"); erp = dasd_3990_erp_action_1 (erp); } else { /* all other data checks */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Uncorrectable data check with retry count " - "exhausted...\n"); + "exhausted..."); erp = dasd_3990_erp_action_5 (erp); } -#else - if (sense[2] & SNS2_ENV_DATA_PRESENT) { - - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Uncorrectable data check recovered secondary " - "addr of duplex pair"); - - erp = dasd_3990_erp_action_4 (erp, - sense); - } -#endif /* ERP_FULL_ERP */ - return erp; } /* end dasd_3990_erp_data_check */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERP_OVERRUN * @@ -1566,21 +1611,20 @@ ccw_req_t * dasd_3990_erp_overrun (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; erp->function = dasd_3990_erp_overrun; - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Overrun - service overrun or overrun" - " error requested by channel\n"); + " error requested by channel"); erp = dasd_3990_erp_action_5 (erp); return erp; } /* end dasd_3990_erp_overrun */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_INV_FORMAT @@ -1597,44 +1641,36 @@ ccw_req_t * dasd_3990_erp_inv_format (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; erp->function = dasd_3990_erp_inv_format; if (sense[2] & SNS2_ENV_DATA_PRESENT) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Track format error when destaging or " "staging data"); -#ifdef ERP_FULL_ERP - dasd_3990_handle_env_data (sense); + dasd_3990_handle_env_data (erp, + sense); erp = dasd_3990_erp_action_4 (erp, sense); } else { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_ERR, device, "%s", "Invalid Track Format - Fatal error should have " - "been handled within the interrupt handler\n"); + "been handled within the interrupt handler"); - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + erp= dasd_3990_erp_cleanup (erp, + CQR_STATUS_FAILED); } -#else - erp = dasd_3990_erp_action_4 (erp, - sense); - } -#endif /* ERP_FULL_ERP */ return erp; } /* end dasd_3990_erp_inv_format */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERP_EOC * @@ -1642,30 +1678,25 @@ dasd_3990_erp_inv_format (ccw_req_t *erp, * Handles 24 byte 'End-of-Cylinder' error. * * PARAMETER - * erp current erp_head + * erp already added default erp * RETURN VALUES - * erp new erp_head - pointer to new ERP + * erp pointer to original (failed) cqr. */ ccw_req_t * -dasd_3990_erp_EOC (ccw_req_t *erp, +dasd_3990_erp_EOC (ccw_req_t *default_erp, char *sense) { - dasd_device_t *device = erp->device; - - erp->function = dasd_3990_erp_EOC; - - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "End-of-Cylinder - must never happen\n"); + dasd_device_t *device = default_erp->device; - /* implement action 7 */ - BUG(); + DASD_MESSAGE (KERN_ERR, device, "%s", + "End-of-Cylinder - must never happen"); - return erp; + /* implement action 7 - BUG */ + return dasd_3990_erp_cleanup (default_erp, + CQR_STATUS_FAILED); } /* end dasd_3990_erp_EOC */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_ENV_DATA @@ -1682,16 +1713,16 @@ ccw_req_t * dasd_3990_erp_env_data (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; erp->function = dasd_3990_erp_env_data; - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Environmental data present"); -#ifdef ERP_FULL_ERP - dasd_3990_handle_env_data (sense); -#endif /* ERP_FULL_ERP */ + + dasd_3990_handle_env_data (erp, + sense); erp = dasd_3990_erp_action_4 (erp, sense); @@ -1700,7 +1731,6 @@ dasd_3990_erp_env_data (ccw_req_t *erp, } /* end dasd_3990_erp_env_data */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERP_NO_REC * @@ -1708,28 +1738,24 @@ dasd_3990_erp_env_data (ccw_req_t *erp, * Handles 24 byte 'No Record Found' error. * * PARAMETER - * erp current erp_head + * erp already added default ERP + * * RETURN VALUES * erp new erp_head - pointer to new ERP */ ccw_req_t * -dasd_3990_erp_no_rec (ccw_req_t *erp, +dasd_3990_erp_no_rec (ccw_req_t *default_erp, char *sense) { - dasd_device_t *device = erp->device; - erp->function = dasd_3990_erp_no_rec; - - DASD_MESSAGE (KERN_WARNING, device, - "%s", + dasd_device_t *device = default_erp->device; + + DASD_MESSAGE (KERN_ERR, device, "%s", "No Record Found - Fatal error should " - "have been handled within the interrupt handler\n"); - - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + "have been handled within the interrupt handler"); - return erp; + return dasd_3990_erp_cleanup (default_erp, + CQR_STATUS_FAILED); } /* end dasd_3990_erp_no_rec */ @@ -1749,22 +1775,16 @@ dasd_3990_erp_no_rec (ccw_req_t *erp, ccw_req_t * dasd_3990_erp_file_prot (ccw_req_t *erp) { - dasd_device_t *device = erp->device; - erp->function = dasd_3990_erp_file_prot; + dasd_device_t *device = erp->device; - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "File Protected\n"); + DASD_MESSAGE (KERN_ERR, device, "%s", + "File Protected"); - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); - - return erp; + return dasd_3990_erp_cleanup (erp, + CQR_STATUS_FAILED); } /* end dasd_3990_erp_file_prot */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_INSPECT_24 @@ -1781,14 +1801,13 @@ dasd_3990_erp_file_prot (ccw_req_t *erp) * erp pointer to the (addtitional) ERP */ ccw_req_t * -dasd_3990_erp_inspect_24 ( ccw_req_t *erp, - char *sense) +dasd_3990_erp_inspect_24 (ccw_req_t *erp, + char *sense) { + ccw_req_t *erp_filled = NULL; - dasd_device_t *device = erp->device; /* Check sense for .... */ -#ifdef ERP_FULL_ERP /* 'Command Reject' */ if ((erp_filled == NULL) && (sense[0] & SNS0_CMD_REJECT)) { @@ -1805,7 +1824,6 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp, (sense[0] & SNS0_BUS_OUT_CHECK)) { erp_filled = dasd_3990_erp_bus_out (erp); } -#endif /* ERP_FULL_ERP */ /* 'Equipment Check' */ if ((erp_filled == NULL) && (sense[0] & SNS0_EQUIPMENT_CHECK)) { @@ -1818,35 +1836,30 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp, erp_filled = dasd_3990_erp_data_check (erp, sense); } -#ifdef ERP_FULL_ERP /* 'Overrun' */ if ((erp_filled == NULL) && (sense[0] & SNS0_OVERRUN)) { erp_filled = dasd_3990_erp_overrun (erp, sense); } -#endif /* ERP_FULL_ERP */ /* 'Invalid Track Format' */ if ((erp_filled == NULL) && (sense[1] & SNS1_INV_TRACK_FORMAT)) { erp_filled = dasd_3990_erp_inv_format (erp, sense); } -#ifdef ERP_FULL_ERP /* 'End-of-Cylinder' */ if ((erp_filled == NULL) && (sense[1] & SNS1_EOC)) { erp_filled = dasd_3990_erp_EOC (erp, sense); } -#endif /* ERP_FULL_ERP */ /* 'Environmental Data' */ if ((erp_filled == NULL) && (sense[2] & SNS2_ENV_DATA_PRESENT)) { erp_filled = dasd_3990_erp_env_data (erp, sense); } -#ifdef ERP_FULL_ERP /* 'No Record Found' */ if ((erp_filled == NULL) && (sense[1] & SNS1_NO_REC_FOUND)) { @@ -1858,15 +1871,9 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp, (sense[1] & SNS1_FILE_PROTECTED)) { erp_filled = dasd_3990_erp_file_prot (erp); } -#endif /* ERP_FULL_ERP */ - - /* other (unknown) error - do default ERP */ + /* other (unknown) error - do default ERP */ if (erp_filled == NULL) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "default ERP taken"); - erp_filled = erp; } @@ -1880,7 +1887,6 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp, ***************************************************************************** */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERPACTION_10_32 * @@ -1898,19 +1904,18 @@ ccw_req_t * dasd_3990_erp_action_10_32 (ccw_req_t *erp, char *sense) { + dasd_device_t *device = erp->device; erp->retries = 256; erp->function = dasd_3990_erp_action_10_32; - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Perform logging requested\n"); + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "Perform logging requested"); return erp; } /* end dasd_3990_erp_action_10_32 */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_ACTION_1B_32 @@ -1924,8 +1929,9 @@ dasd_3990_erp_action_10_32 (ccw_req_t *erp, * action because it contains no DE/LO data space. * * PARAMETER - * default_erp already created default erp. + * default_erp already added default erp. * sense current sense data + * * RETURN VALUES * erp new erp or * default_erp in case of imprecise ending or error @@ -1934,6 +1940,7 @@ ccw_req_t * dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, char *sense) { + dasd_device_t *device = default_erp->device; __u32 cpa = 0; ccw_req_t *cqr; @@ -1942,14 +1949,14 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, char *LO_data; /* LO_eckd_data_t */ ccw1_t *ccw; - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Write not finsihed because of unexpected condition"); + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "Write not finished because of unexpected condition"); default_erp->function = dasd_3990_erp_action_1B_32; /* determine the original cqr */ cqr = default_erp; + while (cqr->refers != NULL){ cqr = cqr->refers; } @@ -1957,8 +1964,7 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, /* for imprecise ending just do default erp */ if (sense[1] & 0x01) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Imprecise ending is set - just retry"); return default_erp; @@ -1970,34 +1976,28 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, if (cpa == 0) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Unable to determine address of the CCW " "to be restarted"); - check_then_set (&default_erp->status, - CQR_STATUS_FILLED, - CQR_STATUS_FAILED); - - return default_erp; + return dasd_3990_erp_cleanup (default_erp, + CQR_STATUS_FAILED); } /* Build new ERP request including DE/LO */ erp = dasd_alloc_request ((char *) &cqr->magic, 2 + 1, /* DE/LO + TIC */ sizeof (DE_eckd_data_t) + - sizeof (LO_eckd_data_t)); + sizeof (LO_eckd_data_t), + device); - if ( !erp ) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + if (!erp) { + + DASD_MESSAGE (KERN_ERR, device, "%s", "Unable to allocate ERP"); - check_then_set (&default_erp->status, - CQR_STATUS_FILLED, - CQR_STATUS_FAILED); - - return default_erp; + return dasd_3990_erp_cleanup (default_erp, + CQR_STATUS_FAILED); } /* use original DE */ @@ -2012,10 +2012,11 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, if ((sense[3] == 0x01) && (LO_data[1] & 0x01) ){ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_ERR, device, "%s", "BUG - this should not happen"); - //BUG(); /* check for read count suffixing n.a. */ + + return dasd_3990_erp_cleanup (default_erp, + CQR_STATUS_FAILED); } if ((sense[7] & 0x3F) == 0x01) { @@ -2043,22 +2044,38 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, ccw = erp->cpaddr; memset (ccw, 0, sizeof (ccw1_t)); ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; - ccw->flags = CCW_FLAG_CC; - ccw->count = 16; - set_normalized_cda (ccw, __pa (DE_data)); + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + if (dasd_set_normalized_cda (ccw, + __pa (DE_data), erp, device)) { + dasd_free_request (erp, device); + DASD_MESSAGE (KERN_ERR, device, "%s", + "Unable to allocate ERP"); + + return dasd_3990_erp_cleanup (default_erp, + CQR_STATUS_FAILED); + } /* create LO ccw */ ccw++; memset (ccw, 0, sizeof (ccw1_t)); ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; - ccw->flags = CCW_FLAG_CC; - ccw->count = 16; - set_normalized_cda (ccw, __pa (LO_data)); + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + if (dasd_set_normalized_cda (ccw, + __pa (LO_data), erp, device)){ + dasd_free_request (erp, device); + DASD_MESSAGE (KERN_ERR, device, "%s", + "Unable to allocate ERP"); + + return dasd_3990_erp_cleanup (default_erp, + CQR_STATUS_FAILED); + } /* TIC to the failed ccw */ ccw++; ccw->cmd_code = CCW_CMD_TIC; - ccw->cda = cpa; + ccw->cda = cpa; /* fill erp related fields */ erp->function = dasd_3990_erp_action_1B_32; @@ -2067,11 +2084,11 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, erp->magic = default_erp->magic; erp->lpm = 0xFF; erp->expires = 0; - erp->retries = 255; + erp->retries = 256; erp->status = CQR_STATUS_FILLED; /* remove the default erp */ - dasd_free_request (default_erp); + dasd_free_request (default_erp, device); return erp; @@ -2096,6 +2113,7 @@ ccw_req_t * dasd_3990_update_1B (ccw_req_t *previous_erp, char *sense) { + dasd_device_t *device = previous_erp->device; __u32 cpa = 0; ccw_req_t *cqr; @@ -2103,13 +2121,13 @@ dasd_3990_update_1B (ccw_req_t *previous_erp, char *LO_data; /* LO_eckd_data_t */ ccw1_t *ccw; - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Write not finsihed because of unexpected condition" + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "Write not finished because of unexpected condition" " - follow on"); /* determine the original cqr */ - cqr = previous_erp; + cqr = previous_erp; + while (cqr->refers != NULL){ cqr = cqr->refers; } @@ -2117,13 +2135,12 @@ dasd_3990_update_1B (ccw_req_t *previous_erp, /* for imprecise ending just do default erp */ if (sense[1] & 0x01) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Imprecise ending is set - just retry"); check_then_set (&previous_erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); return previous_erp; } @@ -2133,16 +2150,8 @@ dasd_3990_update_1B (ccw_req_t *previous_erp, cpa = previous_erp->dstat->cpa; if (cpa == 0) { - ccw = cqr->cpaddr; /* addr of first data transfer */ - ccw++; /* command in domain */ - ccw++; - cpa = (__u32) ccw; - } - - if (cpa == 0) { - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "Unable to determine address of the CCW " "to be restarted"); @@ -2161,10 +2170,14 @@ dasd_3990_update_1B (ccw_req_t *previous_erp, if ((sense[3] == 0x01) && (LO_data[1] & 0x01) ){ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_ERR, device, "%s", "BUG - this should not happen"); - //BUG(); /* check for read count suffixing n.a. */ + + check_then_set (&previous_erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return previous_erp; } if ((sense[7] & 0x3F) == 0x01) { @@ -2202,12 +2215,14 @@ dasd_3990_update_1B (ccw_req_t *previous_erp, } /* end dasd_3990_update_1B */ -#ifdef ERP_FULL_ERP /* * DASD_3990_ERP_COMPOUND_RETRY * * DESCRIPTION * Handles the compound ERP action retry code. + * NOTE: At least one retry is done even if zero is specified + * by the sense data. This makes enqueueing of the request + * easier. * * PARAMETER * sense sense data of the actual error @@ -2221,41 +2236,30 @@ void dasd_3990_erp_compound_retry (ccw_req_t *erp, char *sense) { + switch (sense[25] & 0x03) { case 0x00: /* no not retry */ - erp->retries = 0; - break; + erp->retries = 1; + break; case 0x01: /* retry 2 times */ erp->retries = 2; - - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); break; case 0x02: /* retry 10 times */ erp->retries = 10; - - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); break; - case 0x03: /* retry 255 times */ - erp->retries = 255; - - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); + case 0x03: /* retry 256 times */ + erp->retries = 256; break; default: BUG(); } - + erp->function = dasd_3990_erp_compound_retry; - + } /* end dasd_3990_erp_compound_retry */ /* @@ -2277,14 +2281,14 @@ void dasd_3990_erp_compound_path (ccw_req_t *erp, char *sense) { - + if (sense[25] & DASD_SENSE_BIT_3) { dasd_3990_erp_alternate_path (erp); if (erp->status == CQR_STATUS_FAILED) { /* reset the lpm and the status to be able to * try further actions. */ - + erp->lpm = LPM_ANYPATH; check_then_set (&erp->status, @@ -2316,7 +2320,6 @@ ccw_req_t * dasd_3990_erp_compound_code (ccw_req_t *erp, char *sense) { - if (sense[25] & DASD_SENSE_BIT_2) { @@ -2337,7 +2340,8 @@ dasd_3990_erp_compound_code (ccw_req_t *erp, break; default: - BUG(); + /* should not happen - continue */ + } } @@ -2367,16 +2371,17 @@ void dasd_3990_erp_compound_config (ccw_req_t *erp, char *sense) { + if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2) ) { /* set to suspended duplex state then restart */ dasd_device_t *device = erp->device; - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Set device to suspended duplex state should be done!\n" - "This is not implemented yet (for compound ERP)\n" + DASD_MESSAGE (KERN_ERR, device, "%s", + "Set device to suspended duplex state should be " + "done!\n" + "This is not implemented yet (for compound ERP)" " - please report to linux390@de.ibm.com"); } @@ -2389,12 +2394,12 @@ dasd_3990_erp_compound_config (ccw_req_t *erp, * DASD_3990_ERP_COMPOUND * * DESCRIPTION - * Does a detailed inspection of the 32 byte sense data - * and sets up a related error recovery action. + * Does the further compound program action if + * compound retry was not successful. * * PARAMETER * sense sense data of the actual error - * erp pointer to the currently created ERP + * erp pointer to the current (failed) ERP * * RETURN VALUES * erp (additional) ERP pointer @@ -2404,33 +2409,23 @@ ccw_req_t * dasd_3990_erp_compound (ccw_req_t *erp, char *sense) { - if ((erp->function != dasd_3990_erp_compound_retry ) && - (erp->function != dasd_3990_erp_compound_path ) && - (erp->function != dasd_3990_erp_compound_code ) && - (erp->function != dasd_3990_erp_compound_config) ) { - /* called first time */ - dasd_3990_erp_compound_retry (erp, - sense); - } - - /* do further action if no retry is specified / left */ if ((erp->function == dasd_3990_erp_compound_retry) && - (erp->status == CQR_STATUS_ERROR ) ){ + (erp->status == CQR_STATUS_ERROR ) ) { dasd_3990_erp_compound_path (erp, sense); } if ((erp->function == dasd_3990_erp_compound_path) && - (erp->status == CQR_STATUS_ERROR ) ){ + (erp->status == CQR_STATUS_ERROR ) ){ erp = dasd_3990_erp_compound_code (erp, sense); } if ((erp->function == dasd_3990_erp_compound_code) && - (erp->status == CQR_STATUS_ERROR ) ){ + (erp->status == CQR_STATUS_ERROR ) ) { dasd_3990_erp_compound_config (erp, sense); @@ -2447,7 +2442,6 @@ dasd_3990_erp_compound (ccw_req_t *erp, return erp; } /* end dasd_3990_erp_compound */ -#endif /* ERP_FULL_ERP */ /* * DASD_3990_ERP_INSPECT_32 @@ -2468,6 +2462,7 @@ ccw_req_t * dasd_3990_erp_inspect_32 ( ccw_req_t *erp, char *sense ) { + dasd_device_t *device = erp->device; erp->function = dasd_3990_erp_inspect_32; @@ -2475,40 +2470,32 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp, if (sense[25] & DASD_SENSE_BIT_0) { /* compound program action codes (byte25 bit 0 == '1') */ -#ifdef ERP_FULL_ERP - erp = dasd_3990_erp_compound (erp, + dasd_3990_erp_compound_retry (erp, sense); -#else - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "default ERP taken"); -#endif /* ERP_FULL_ERP */ } else { /* single program action codes (byte25 bit 0 == '0') */ switch (sense[25]) { -#ifdef ERP_FULL_ERP + case 0x00: /* success */ - DASD_MESSAGE (KERN_WARNING, device, + DASD_MESSAGE (KERN_DEBUG, device, "ERP called for successful request %p" " - NO ERP necessary", erp); + + erp = dasd_3990_erp_cleanup (erp, + CQR_STATUS_DONE); - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_DONE); break; case 0x01: /* fatal error */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "Fatal error should " - "have been handled within the interrupt handler\n"); + DASD_MESSAGE (KERN_ERR, device, "%s", + "Fatal error should have been " + "handled within the interrupt handler"); - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + erp = dasd_3990_erp_cleanup (erp, + CQR_STATUS_FAILED); break; case 0x02: /* intervention required */ @@ -2517,15 +2504,15 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp, break; case 0x0F: /* length mismatch during update write command */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "update write command error - should not happen; " - "Please send this message together with the above " - "sense data to linux390@de.ibm.com\n"); - - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + DASD_MESSAGE (KERN_ERR, device, "%s", + "update write command error - should not " + "happen;\n" + "Please send this message together with " + "the above sense data to linux390@de." + "ibm.com"); + + erp = dasd_3990_erp_cleanup (erp, + CQR_STATUS_FAILED); break; case 0x10: /* logging required for other channel program */ @@ -2534,17 +2521,16 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp, break; case 0x15: /* next track outside defined extend */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "next track outside defined extend - should not happen; " - "Please send this message together with the above " - "sense data to linux390@de.ibm.com\n"); - - check_then_set (&erp->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + DASD_MESSAGE (KERN_ERR, device, "%s", + "next track outside defined extend - " + "should not happen;\n" + "Please send this message together with " + "the above sense data to linux390@de." + "ibm.com"); + + erp= dasd_3990_erp_cleanup (erp, + CQR_STATUS_FAILED); break; -#endif /* ERP_FULL_ERP */ case 0x1B: /* unexpected condition during write */ @@ -2552,22 +2538,18 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp, sense); break; -#ifdef ERP_FULL_ERP case 0x1C: /* invalid data */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_EMERG, device, "%s", "Data recovered during retry with PCI " - "fetch mode active\n"); + "fetch mode active"); /* not possible to handle this situation in Linux */ - panic("No way to inform appliction about the possibly " - "incorret data"); + panic("Invalid data - No way to inform appliction about " + "the possibly incorret data"); break; -#endif /* ERP_FULL_ERP */ case 0x1D: /* state-change pending */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "A State change pending condition exists " "for the subsystem or device"); @@ -2575,10 +2557,8 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp, sense); break; - default: /* all others errors */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", - "default ERP taken"); + default: /* all others errors - default erp */ + } } @@ -2607,6 +2587,7 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp, ccw_req_t * dasd_3990_erp_inspect (ccw_req_t *erp) { + ccw_req_t *erp_new = NULL; /* sense data are located in the refers record of the */ /* already set up new ERP ! */ @@ -2648,24 +2629,34 @@ dasd_3990_erp_inspect (ccw_req_t *erp) ccw_req_t * dasd_3990_erp_add_erp (ccw_req_t *cqr) { + + dasd_device_t *device = cqr->device; + /* allocate additional request block */ - ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); - if ( !erp ) { - printk( KERN_WARNING PRINTK_HEADER - "unable to allocate ERP request\n" ); - return NULL; + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device); + + if (!erp) { + + DASD_MESSAGE (KERN_ERR, device, "%s", + "Unable to allocate ERP request"); + + check_then_set (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return cqr; } /* initialize request with default TIC to current ERP/CQR */ erp->cpaddr->cmd_code = CCW_CMD_TIC; - erp->cpaddr->cda = ((__u32) cqr->cpaddr); + erp->cpaddr->cda = (long)(cqr->cpaddr); erp->function = dasd_3990_erp_add_erp; erp->refers = cqr; erp->device = cqr->device; erp->magic = cqr->magic; erp->lpm = 0xFF; erp->expires = 0; - erp->retries = 255; + erp->retries = 256; erp->status = CQR_STATUS_FILLED; @@ -2697,7 +2688,8 @@ dasd_3990_erp_additional_erp (ccw_req_t *cqr) erp = dasd_3990_erp_add_erp (cqr); /* inspect sense, determine specific ERP if possible */ - if (erp != NULL) { + if (erp != cqr) { + erp = dasd_3990_erp_inspect (erp); } @@ -2727,13 +2719,13 @@ int dasd_3990_erp_error_match (ccw_req_t *cqr1, ccw_req_t *cqr2) { + /* check failed CCW */ if (cqr1->dstat->cpa != cqr2->dstat->cpa) { // return 0; /* CCW doesn't match */ - printk(KERN_WARNING PRINTK_HEADER - "_error_match: CCW doesn't match -> ignore\n"); } + /* check sense data; byte 0-2,25,27 */ if (!((strncmp (cqr1->dstat->ii.sense.data, cqr2->dstat->ii.sense.data, @@ -2745,9 +2737,10 @@ dasd_3990_erp_error_match (ccw_req_t *cqr1, return 0; /* sense doesn't match */ } + return 1; /* match */ -} /* end dasd_3990_erp_error_match */ +} /* end dasd_3990_erp_error_match */ /* * DASD_3990_ERP_IN_ERP @@ -2760,35 +2753,38 @@ dasd_3990_erp_error_match (ccw_req_t *cqr1, * cqr failed cqr (either original cqr or already an erp) * * RETURN VALUES - * erp erp-pointer to the already defined error recovery procedure OR + * erp erp-pointer to the already defined error + * recovery procedure OR * NULL if a 'new' error occurred. */ ccw_req_t * dasd_3990_erp_in_erp (ccw_req_t *cqr) { - ccw_req_t *erp_head = cqr, /* save erp chain head */ - *erp_match = NULL; /* save erp chain head */ + + ccw_req_t *erp_head = cqr, /* save erp chain head */ + *erp_match = NULL; /* save erp chain head */ int match = 0; /* 'boolean' for matching error found */ if (cqr->refers == NULL) { /* return if not in erp */ return NULL; } + /* check the erp/cqr chain for current error */ do { match = dasd_3990_erp_error_match (erp_head, cqr->refers); - erp_match = cqr; /* save possible matching erp */ - cqr = cqr->refers; /* check next erp/cqr in queue */ + erp_match = cqr; /* save possible matching erp */ + cqr = cqr->refers; /* check next erp/cqr in queue */ + } while ((cqr->refers != NULL) && - (match == 0)); + (!match ) ); - if (match) { - return erp_match; /* return address of matching erp */ - } else { - return NULL; /* return NULL to indicate that no match - was found */ + if (!match) { + return NULL; /* no match was found */ } + return erp_match; /* return address of matching erp */ + } /* END dasd_3990_erp_in_erp */ /* @@ -2810,9 +2806,10 @@ dasd_3990_erp_in_erp (ccw_req_t *cqr) ccw_req_t * dasd_3990_erp_further_erp (ccw_req_t *erp) { - dasd_device_t *device = erp->device; + + dasd_device_t *device = erp->device; + char *sense = erp->dstat->ii.sense.data; -#ifdef ERP_FULL_ERP /* check for 24 byte sense ERP */ if ((erp->function == dasd_3990_erp_bus_out ) || (erp->function == dasd_3990_erp_action_1) || @@ -2823,8 +2820,6 @@ dasd_3990_erp_further_erp (ccw_req_t *erp) } else if (erp->function == dasd_3990_erp_action_5) { /* retries have not been successful */ - char *sense = erp->dstat->ii.sense.data; - /* prepare erp for retry on different channel path */ erp = dasd_3990_erp_action_1 (erp); @@ -2853,26 +2848,25 @@ dasd_3990_erp_further_erp (ccw_req_t *erp) break; } default: - DASD_MESSAGE (KERN_WARNING, device, - "invalid subcommand modifier 0x%x for " - "Diagnostic Control Command", + DASD_MESSAGE (KERN_DEBUG, device, + "invalid subcommand modifier 0x%x " + "for Diagnostic Control Command", sense[25]); } } -// /* check for 32 byte sense ERP */ -// } else if ((erp->function == dasd_3990_erp_xxx){ -#else - /* check for 24 byte sense ERP */ - if ((erp->function == dasd_3990_erp_action_1) || - (erp->function == dasd_3990_erp_action_4) ){ - - erp = dasd_3990_erp_action_1 (erp); -#endif /* ERP_FULL_ERP */ + /* check for 32 byte sense ERP */ + } else if ((erp->function == dasd_3990_erp_compound_retry ) || + (erp->function == dasd_3990_erp_compound_path ) || + (erp->function == dasd_3990_erp_compound_code ) || + (erp->function == dasd_3990_erp_compound_config) ) { + erp = dasd_3990_erp_compound (erp, + sense); + } else { /* no retry left and no additional special handling necessary */ - DASD_MESSAGE (KERN_WARNING, device, + DASD_MESSAGE (KERN_ERR, device, "no retries left for erp %p - " "set status to FAILED", erp); @@ -2892,102 +2886,87 @@ dasd_3990_erp_further_erp (ccw_req_t *erp) * DESCRIPTION * An error occurred again and an ERP has been detected which is already * used to handle this error (e.g. retries). - * All prior ERP's are set to status DONE and the retry counter is - * decremented. - * If retry counter is already 0, it has to checked if further action - * is needed (besides retry) or if the ERP has failed. + * All prior ERP's are asumed to be successful and therefore removed + * from queue. + * If retry counter of matching erp is already 0, it is checked if further + * action is needed (besides retry) or if the ERP has failed. * * PARAMETER * erp_head first ERP in ERP-chain - * erp_match ERP that handles the actual error. + * erp ERP that handles the actual error. + * (matching erp) * * RETURN VALUES - * none + * erp modified/additional ERP */ -void +ccw_req_t * dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head, - ccw_req_t *erp_match) + ccw_req_t *erp) { dasd_device_t *device = erp_head->device; - ccw_req_t *erp_done = erp_head; + ccw_req_t *erp_done = erp_head; /* finished req */ ccw_req_t *erp_free = NULL; /* req to be freed */ - + /* loop over successful ERPs and remove them from chanq */ - while ((erp_done != erp_match) && - (erp_done != NULL)) { + while (erp_done != erp) { -#ifdef ERP_DEBUG - DASD_MESSAGE (KERN_WARNING, device, - "successful ERP - dequeue and free request %p", - (void *) erp_done); -#endif /* ERP_DEBUG */ - - check_then_set (&erp_done->status, - CQR_STATUS_ERROR, - CQR_STATUS_DONE); + if (erp_done == NULL) /* end of chain reached */ + panic (PRINTK_HEADER "Programming error in ERP! The " + "original request was lost\n"); /* remove the request from the device queue */ dasd_chanq_deq (&device->queue, erp_done); - + erp_free = erp_done; erp_done = erp_done->refers; /* free the finished erp request */ - dasd_free_request (erp_free); + dasd_free_request (erp_free, erp_free->device); - } - - if (erp_done == NULL) /* erp_done should never be NULL! */ - panic (PRINTK_HEADER "Programming error in ERP! The original " - "request was lost\n"); + } /* end while */ -#ifdef ERP_DEBUG - /* handle matching ERP */ - DASD_MESSAGE (KERN_WARNING, device, - "handle matching erp %p", - (void *) erp_done); -#endif - - if (erp_done->retries > 0) { + if (erp->retries > 0) { + + char *sense = erp->dstat->ii.sense.data; /* check for special retries */ - if (erp_done->function == dasd_3990_erp_action_4) { - char *sense = erp_done->dstat->ii.sense.data; - erp_done = dasd_3990_erp_action_4 (erp_done, - sense); + if (erp->function == dasd_3990_erp_action_4) { - } else if (erp_done->function == dasd_3990_erp_action_1B_32) { - char *sense = erp_done->dstat->ii.sense.data; - erp_done = dasd_3990_update_1B (erp_done, - sense); - -#ifdef ERP_FULL_ERP - } else if (erp_done->function == dasd_3990_erp_int_req) { - erp_done = dasd_3990_erp_int_req (erp_done); -#endif /* ERP_FULL_ERP */ + erp = dasd_3990_erp_action_4 (erp, + sense); + + } else if (erp->function == dasd_3990_erp_action_1B_32) { + + erp = dasd_3990_update_1B (erp, + sense); + + } else if (erp->function == dasd_3990_erp_int_req) { + + erp = dasd_3990_erp_int_req (erp); } else { /* simple retry */ - DASD_MESSAGE (KERN_WARNING, device, + DASD_MESSAGE (KERN_DEBUG, device, "%i retries left for erp %p", - erp_done->retries, - (void *) erp_done); + erp->retries, + erp); /* handle the request again... */ - check_then_set (&erp_done->status, + check_then_set (&erp->status, CQR_STATUS_ERROR, CQR_STATUS_QUEUED); } + } else { /* no retry left - check for further necessary action */ /* if no further actions, handle rest as permanent error */ - erp_done = dasd_3990_erp_further_erp (erp_done); + erp = dasd_3990_erp_further_erp (erp); } - erp_head = erp_done; - + return erp; + } /* end dasd_3990_erp_handle_match_erp */ /* @@ -3004,30 +2983,27 @@ dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head, * erp erp-pointer to the head of the ERP action chain. * This means: * - either a ptr to an additional ERP cqr or - * - the original given cqr (which's status might be modified) + * - the original given cqr (which's status might + * be modified) */ ccw_req_t * dasd_3990_erp_action (ccw_req_t *cqr) { + ccw_req_t *erp = NULL; dasd_device_t *device = cqr->device; + __u32 cpa = cqr->dstat->cpa; #ifdef ERP_DEBUG - __u32 cpa = cqr->dstat->cpa; -#endif /* ERP_DEBUG */ - -#ifdef ERP_DEBUG - - printk (KERN_WARNING PRINTK_HEADER - "entering 3990 ERP for " - "0x%04X on sch %d = /dev/%s \n", - device->devinfo.devno, - device->devinfo.irq, - device->name); + DASD_MESSAGE (KERN_DEBUG, device, + "entering 3990 ERP for " + "0x%04X on sch %d = /dev/%s ", + device->devinfo.devno, + device->devinfo.irq, + device->name); /* print current erp_chain */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "ERP chain at BEGINNING of ERP-ACTION"); { ccw_req_t *temp_erp = NULL; @@ -3035,23 +3011,24 @@ dasd_3990_erp_action (ccw_req_t *cqr) temp_erp != NULL; temp_erp = temp_erp->refers){ - DASD_MESSAGE (KERN_WARNING, device, - " erp %p refers to %p \n", + DASD_MESSAGE (KERN_DEBUG, device, + " erp %p refers to %p", temp_erp, temp_erp->refers); } } -#endif +#endif /* ERP_DEBUG */ /* double-check if current erp/cqr was successfull */ - if ((cqr->dstat->cstat == 0x00) && - (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { - DASD_MESSAGE (KERN_WARNING, device, + if ((cqr->dstat->cstat == 0x00 ) && + (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ) { + + DASD_MESSAGE (KERN_DEBUG, device, "ERP called for successful request %p" " - NO ERP necessary", cqr); - check_then_set (&erp->status, + check_then_set (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_DONE); @@ -3059,12 +3036,12 @@ dasd_3990_erp_action (ccw_req_t *cqr) } /* check if sense data are available */ if (!cqr->dstat->ii.sense.data) { - DASD_MESSAGE (KERN_WARNING, device, + DASD_MESSAGE (KERN_DEBUG, device, "ERP called witout sense data avail ..." "request %p - NO ERP possible", cqr); - check_then_set (&erp->status, + check_then_set (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); @@ -3080,40 +3057,180 @@ dasd_3990_erp_action (ccw_req_t *cqr) erp = dasd_3990_erp_additional_erp (cqr); } else { /* matching erp found - set all leading erp's to DONE */ - dasd_3990_erp_handle_match_erp (cqr, erp); - erp = cqr; + erp = dasd_3990_erp_handle_match_erp (cqr, + erp); } #ifdef ERP_DEBUG /* print current erp_chain */ - DASD_MESSAGE (KERN_WARNING, device, - "%s", + DASD_MESSAGE (KERN_DEBUG, device, "%s", "ERP chain at END of ERP-ACTION"); { ccw_req_t *temp_erp = NULL; for (temp_erp = erp; temp_erp != NULL; - temp_erp = temp_erp->refers){ + temp_erp = temp_erp->refers) { - DASD_MESSAGE (KERN_WARNING, device, - " erp %p refers to %p \n", + DASD_MESSAGE (KERN_DEBUG, device, + " erp %p refers to %p", temp_erp, temp_erp->refers); } } #endif /* ERP_DEBUG */ -#ifdef ERP_DEBUG if (erp->status == CQR_STATUS_FAILED) { - log_erp_chain (erp, 1, cpa); + + log_erp_chain (erp, + 1, + cpa); + } + + /* enqueue added ERP request */ + if ((erp != cqr ) && + (erp->status == CQR_STATUS_FILLED) ){ + + dasd_chanq_enq_head (&device->queue, + erp); + } else { + if ((erp->status == CQR_STATUS_FILLED )|| + (erp != cqr ) ){ + /* something strange happened - log the error and throw a BUG() */ + DASD_MESSAGE (KERN_ERR, device, "%s", + "Problems with ERP chain!!! BUG"); + + /* print current erp_chain */ + DASD_MESSAGE (KERN_DEBUG, device, "%s", + "ERP chain at END of ERP-ACTION"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; + temp_erp != NULL; + temp_erp = temp_erp->refers) { + + DASD_MESSAGE (KERN_DEBUG, device, + " erp %p (function %p) refers to %p", + temp_erp, + temp_erp->function, + temp_erp->refers); + } + } + BUG(); + } + } -#endif /* ERP_DEBUG */ return erp; } /* end dasd_3990_erp_action */ /* + * DASD_3990_ERP_POSTACTION + * + * DESCRIPTION + * Frees all ERPs of the current ERP Chain and set the status + * of the original CQR either to CQR_STATUS_DONE if ERP was successful + * or to CQR_STATUS_FAILED if ERP was NOT successful. + * + * PARAMETER + * erp current erp_head + * + * RETURN VALUES + * cqr pointer to the original CQR + */ +ccw_req_t * +dasd_3990_erp_postaction (ccw_req_t *erp) +{ + + ccw_req_t *cqr = NULL, + *free_erp = NULL; + dasd_device_t *device = erp->device; + int success; + + if (erp->refers == NULL || + erp->function == NULL ) { + + BUG (); + } + + if (erp->status == CQR_STATUS_DONE) + success = 1; + else + success = 0; + +#ifdef ERP_DEBUG + + /* print current erp_chain */ + printk (KERN_DEBUG PRINTK_HEADER + "3990 ERP postaction called for erp chain:\n"); + { + ccw_req_t *temp_erp = NULL; + + for (temp_erp = erp; + temp_erp != NULL; + temp_erp = temp_erp->refers) { + + printk (KERN_DEBUG PRINTK_HEADER + " erp %p refers to %p with erp function %p\n", + temp_erp, temp_erp->refers, temp_erp->function); + } + } + +#endif /* ERP_DEBUG */ + + /* free all ERPs - but NOT the original cqr */ + while (erp->refers != NULL) { + + free_erp = erp; + erp = erp->refers; + + /* remove the request from the device queue */ + dasd_chanq_deq (&device->queue, + free_erp); + + /* free the finished erp request */ + dasd_free_request (free_erp, free_erp->device); + } + + /* save ptr to original cqr */ + cqr = erp; + + /* set corresponding status to original cqr */ + if (success) { + + check_then_set (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + } else { + + check_then_set (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + +#ifdef ERP_DEBUG + /* print current erp_chain */ + printk (KERN_DEBUG PRINTK_HEADER + "3990 ERP postaction finished with remaining chain:\n"); + { + ccw_req_t *temp_erp = NULL; + + for (temp_erp = cqr; + temp_erp != NULL; + temp_erp = temp_erp->refers) { + + printk (KERN_DEBUG PRINTK_HEADER + " erp %p refers to %p \n", temp_erp, + temp_erp->refers); + } + } +#endif /* ERP_DEBUG */ + + return cqr; + +} /* end dasd_3990_erp_postaction */ + +/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end diff --git a/drivers/s390/block/dasd_3990_erp.h b/drivers/s390/block/dasd_3990_erp.h index 57d675eabafd..c2a5e0b8317b 100644 --- a/drivers/s390/block/dasd_3990_erp.h +++ b/drivers/s390/block/dasd_3990_erp.h @@ -10,7 +10,6 @@ #ifndef DASD_3990_ERP_H #define DASD_3990_ERP_H - dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *); ccw_req_t *dasd_3990_erp_action (ccw_req_t *); @@ -19,10 +18,9 @@ ccw_req_t *dasd_2105_erp_action (ccw_req_t *); void dasd_3990_erp_restart_queue (unsigned long); typedef struct DCTL_data_t { - unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */ - unsigned char modifier; /* Subcommand modifier */ - unsigned short res; /* reserved */ + unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */ + unsigned char modifier; /* Subcommand modifier */ + unsigned short res; /* reserved */ } __attribute__ ((packed)) DCTL_data_t; - -#endif /* DASD_3990_ERP_H */ +#endif /* DASD_3990_ERP_H */ diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c index 9ece67cc9b00..e8293701f6d3 100644 --- a/drivers/s390/block/dasd_9336_erp.c +++ b/drivers/s390/block/dasd_9336_erp.c @@ -6,7 +6,8 @@ */ #include <asm/ccwcache.h> -#include <asm/dasd.h> +#include "dasd_int.h" +#include "dasd_9336_erp.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER @@ -29,15 +30,12 @@ * dasd_era_fatal for all fatal (unrecoverable errors) * dasd_era_recover for all others. */ -dasd_era_t -dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat) +dasd_era_t dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat) { - char *sense = stat->ii.sense.data; - /* check for successful execution first */ if (stat->cstat == 0x00 && stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; + return dasd_era_none; /* examine the 24 byte sense data */ return dasd_era_recover; diff --git a/drivers/s390/block/dasd_9336_erp.h b/drivers/s390/block/dasd_9336_erp.h new file mode 100644 index 000000000000..ec361386c141 --- /dev/null +++ b/drivers/s390/block/dasd_9336_erp.h @@ -0,0 +1,15 @@ +/* + * File...........: linux/drivers/s390/block/dasd_9336_erp.h + * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_9336_ERP_H +#define DASD_9336_ERP_H + +dasd_era_t dasd_9336_erp_examine (ccw_req_t *, devstat_t *); + +#endif /* DASD_3990_ERP_H */ diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c index 5faaebe1f9a8..77fee4896473 100644 --- a/drivers/s390/block/dasd_9343_erp.c +++ b/drivers/s390/block/dasd_9343_erp.c @@ -6,18 +6,17 @@ */ #include <asm/ccwcache.h> -#include <asm/dasd.h> +#include "dasd_int.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER #define PRINTK_HEADER "dasd_erp(9343)" #endif /* PRINTK_HEADER */ -dasd_era_t -dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat) +dasd_era_t dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat) { if (stat->cstat == 0x00 && stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; + return dasd_era_none; return dasd_era_recover; } diff --git a/drivers/s390/block/dasd_9343_erp.h b/drivers/s390/block/dasd_9343_erp.h index b3cf273cf85a..560dac500888 100644 --- a/drivers/s390/block/dasd_9343_erp.h +++ b/drivers/s390/block/dasd_9343_erp.h @@ -10,9 +10,8 @@ #ifndef DASD_9343_ERP_H #define DASD_9343_ERP_H - dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *); ccw_req_t *dasd_9343_erp_action (ccw_req_t *); -#endif /* DASD_9343_ERP_H */ +#endif /* DASD_9343_ERP_H */ diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 945d21938c2e..be5ac9e8be84 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -14,6 +14,7 @@ * fixed partition handling and HDIO_GETGEO */ +#include <linux/config.h> #include <linux/stddef.h> #include <linux/kernel.h> #include <asm/debug.h> @@ -29,6 +30,7 @@ #include <asm/irq.h> #include <asm/s390dyn.h> +#include "dasd_int.h" #include "dasd_diag.h" #ifdef PRINTK_HEADER @@ -39,7 +41,7 @@ dasd_discipline_t dasd_diag_discipline; typedef struct -dasd_diag_private_t { + dasd_diag_private_t { dasd_diag_characteristics_t rdc_data; diag_rw_io_t iob; diag_init_io_t iib; @@ -64,10 +66,8 @@ dia210 (void *devchar) ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" - " .long 0b,2b\n" - ".previous\n" - :"=d" (rc) - :"d" ((void *) __pa (devchar)) + " .long 0b,2b\n" ".previous\n":"=d" (rc) + :"d" ((void *) __pa (devchar)) :"1"); return rc; } @@ -75,11 +75,11 @@ dia210 (void *devchar) static __inline__ int dia250 (void *iob, int cmd) { - __asm__ __volatile__ (" lr 0,%1\n" - " diag 0,%0,0x250\n" - "0: ipm %0\n" - " srl %0,28\n" - " or %0,1\n" + __asm__ __volatile__ (" lr 0,%1\n" + " diag 0,%0,0x250\n" + "0: ipm %0\n" + " srl %0,28\n" + " or %0,1\n" "1:\n" ".section .fixup,\"ax\"\n" "2: lhi %0,3\n" @@ -90,12 +90,10 @@ dia250 (void *iob, int cmd) ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" - " .long 0b,2b\n" - ".previous\n" - : "+d" (cmd) - : "d" ((void *) __pa (iob)) - : "0", "1", "cc" ); - return cmd; + " .long 0b,2b\n" ".previous\n":"+d" (cmd) + :"d" ((void *) __pa (iob)) + :"0", "1", "cc"); + return cmd; } static __inline__ int @@ -115,7 +113,7 @@ mdsk_init_io (dasd_device_t * device, int blocksize, int offset, int size) rc = dia250 (iib, INIT_BIO); - return rc&3; + return rc & 3; } static __inline__ int @@ -128,7 +126,7 @@ mdsk_term_io (dasd_device_t * device) memset (iib, 0, sizeof (diag_init_io_t)); iib->dev_nr = device->devinfo.devno; rc = dia250 (iib, TERM_BIO); - return rc&3; + return rc & 3; } int @@ -154,20 +152,17 @@ dasd_start_diag (ccw_req_t * cqr) if (rc > 8) { PRINT_WARN ("dia250 returned CC %d\n", rc); check_then_set (&cqr->status, - CQR_STATUS_QUEUED, - CQR_STATUS_ERROR); - } else if (rc == 0 ) { - check_then_set(&cqr->status, - CQR_STATUS_QUEUED, - CQR_STATUS_DONE); - dasd_schedule_bh(device); - } else { + CQR_STATUS_QUEUED, CQR_STATUS_ERROR); + } else if (rc == 0) { + check_then_set (&cqr->status, + CQR_STATUS_QUEUED, CQR_STATUS_DONE); + dasd_schedule_bh (device); + } else { if (cqr->expires) { cqr->expires += cqr->startclk; } check_then_set (&cqr->status, - CQR_STATUS_QUEUED, - CQR_STATUS_IN_IO); + CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); rc = 0; } return rc; @@ -176,22 +171,26 @@ dasd_start_diag (ccw_req_t * cqr) void dasd_ext_handler (struct pt_regs *regs, __u16 code) { + int cpu = smp_processor_id(); ccw_req_t *cqr; int ip = S390_lowcore.ext_params; - char status = *((char *) S390_lowcore.ext_params + 5); + char status = *((char *) &S390_lowcore.ext_params + 5); dasd_device_t *device; int done_fast_io = 0; int devno; + irq_enter(cpu, -1); + if (!ip) { /* no intparm: unsolicited interrupt */ printk (KERN_WARNING PRINTK_HEADER "caught unsolicited interrupt\n"); + irq_exit(cpu, -1); return; } if (ip & 0x80000001) { printk (KERN_WARNING PRINTK_HEADER - "caught spurious interrupt with parm %08x\n", - ip); + "caught spurious interrupt with parm %08x\n", ip); + irq_exit(cpu, -1); return; } cqr = (ccw_req_t *) ip; @@ -201,7 +200,8 @@ dasd_ext_handler (struct pt_regs *regs, __u16 code) printk (KERN_WARNING PRINTK_HEADER " INT on devno 0x%04X = /dev/%s (%d:%d)" " belongs to NULL device\n", - devno, device->name, MAJOR (device->kdev), MINOR (device->kdev)); + devno, device->name, MAJOR (device->kdev), + MINOR (device->kdev)); } if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) { printk (KERN_WARNING PRINTK_HEADER @@ -211,18 +211,15 @@ dasd_ext_handler (struct pt_regs *regs, __u16 code) devno, device->name, MAJOR (device->kdev), MINOR (device->kdev), cqr->magic, *(int *) (&device->discipline->name)); + irq_exit(cpu, -1); return; } asm volatile ("STCK %0":"=m" (cqr->stopclk)); switch (status) { case 0x00: check_then_set (&cqr->status, - CQR_STATUS_IN_IO, - CQR_STATUS_DONE); - if ( device->level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING) - device->level = DASD_DEVICE_LEVEL_ANALYSIS_PREPARED; - if (cqr->next && - (cqr->next->status == CQR_STATUS_QUEUED)) { + CQR_STATUS_IN_IO, CQR_STATUS_DONE); + if (cqr->next && (cqr->next->status == CQR_STATUS_QUEUED)) { if (dasd_start_diag (cqr->next) == 0) { done_fast_io = 1; } @@ -233,12 +230,12 @@ dasd_ext_handler (struct pt_regs *regs, __u16 code) case 0x03: default: check_then_set (&cqr->status, - CQR_STATUS_IN_IO, - CQR_STATUS_FAILED); + CQR_STATUS_IN_IO, CQR_STATUS_FAILED); break; } wake_up (&device->wait_q); dasd_schedule_bh (device); + irq_exit(cpu, -1); } static int @@ -255,47 +252,46 @@ dasd_diag_check_characteristics (struct dasd_device_t *device) if (device == NULL) { printk (KERN_WARNING PRINTK_HEADER - "Null device pointer passed to characteristics checker\n"); + "Null device pointer passed to characteristics checker\n"); return -ENODEV; } - if (device->private != NULL) { - kfree (device->private); - } - device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; + device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL); + if (device->private == NULL) { + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + rc = -ENOMEM; + goto fail; } private = (dasd_diag_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); - + rdc_data->dev_nr = device->devinfo.devno; rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t); - - if (dia210 (rdc_data) != 0) { - goto nodiag; + + rc = dia210 (rdc_data); + if ( rc != 0) { + goto fail; } if (rdc_data->vdev_class != DEV_CLASS_FBA && rdc_data->vdev_class != DEV_CLASS_ECKD && rdc_data->vdev_class != DEV_CLASS_CKD) { - goto nodiag; + rc = -ENOTSUPP; + goto fail; } #if 0 printk (KERN_INFO PRINTK_HEADER "%04X: %04X on real %04X/%02X\n", rdc_data->dev_nr, - rdc_data->vdev_type, - rdc_data->rdev_type, rdc_data->rdev_model); + rdc_data->vdev_type, rdc_data->rdev_type, rdc_data->rdev_model); #endif /* Figure out position of label block */ if (private->rdc_data.vdev_class == DEV_CLASS_FBA) { - label_block = 1; + device->sizes.pt_block = 1; } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD || private->rdc_data.vdev_class == DEV_CLASS_CKD) { - label_block = 2; + device->sizes.pt_block = 2; } else { - goto nodiag; + BUG(); } private->label = (long *) get_free_page (GFP_KERNEL); label = private->label; @@ -304,86 +300,69 @@ dasd_diag_check_characteristics (struct dasd_device_t *device) for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) { diag_bio_t *bio; diag_rw_io_t *iob = &private->iob; - + rc = mdsk_init_io (device, bsize, 0, 64); if (rc > 4) { continue; } - cqr = ccw_alloc_request (dasd_diag_discipline.name, sizeof(diag_bio_t)/sizeof(ccw1_t), 0); + cqr = dasd_alloc_request (dasd_diag_discipline.name, + sizeof (diag_bio_t) / sizeof (ccw1_t), + 0, device); if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER - "No memory to allocate initialization request\n"); - free_page((long)private->label); - kfree(private); - device->private = NULL; - return -ENOMEM; + "No memory to allocate initialization request\n"); + free_page ((long) private->label); + rc = -ENOMEM; + goto fail; } bio = (diag_bio_t *) (cqr->cpaddr); memset (bio, 0, sizeof (diag_bio_t)); bio->type = MDSK_READ_REQ; - bio->block_number = label_block + 1; + bio->block_number = device->sizes.pt_block + 1; bio->buffer = __pa (private->label); cqr->device = device; - cqr->status= CQR_STATUS_FILLED; + cqr->status = CQR_STATUS_FILLED; memset (iob, 0, sizeof (diag_rw_io_t)); iob->dev_nr = rdc_data->dev_nr; iob->block_count = 1; - iob->interrupt_params = (u32)cqr; + iob->interrupt_params = (u32) cqr; iob->bio_list = __pa (bio); rc = dia250 (iob, RW_BIO); if (rc == 0) { - if (label[3] != bsize) { - goto nodiag; - } - if (label[0] != 0xc3d4e2f1) { /* != CMS1 */ - goto nodiag; - } - if (label[13] == 0) { - goto nodiag; + if (label[3] != bsize || + label[0] != 0xc3d4e2f1 || /* != CMS1 */ + label[13] == 0 ){ + rc = -EMEDIUMTYPE; + goto fail; } break; } mdsk_term_io (device); } - if ( bsize > PAGE_SIZE ) - goto nodiag; + if (bsize > PAGE_SIZE) { + rc = -EMEDIUMTYPE; + goto fail; + } + device->sizes.blocks = label[7]; device->sizes.bp_block = bsize; device->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */ for (sb = 512; sb < bsize; sb = sb << 1) device->sizes.s2b_shift++; - goto good; - nodiag: - kfree(private); - device -> private = NULL; - rc = -ENODEV; - good: - return rc; -} - -static int -dasd_diag_do_analysis (struct dasd_device_t *device) -{ - dasd_diag_private_t *private = (dasd_diag_private_t *) device->private; - - long *label = private->label; - - /* real size of the volume */ - device->sizes.blocks = label[7]; - if (private->rdc_data.vdev_class == DEV_CLASS_FBA) { - device->sizes.pt_block = 1; - } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD || - private->rdc_data.vdev_class == DEV_CLASS_CKD) { - device->sizes.pt_block = 2; - } else { - return -EINVAL; - } printk (KERN_INFO PRINTK_HEADER "/dev/%s (%04X): capacity (%dkB blks): %ldkB\n", device->name, device->devinfo.devno, (device->sizes.bp_block >> 10), (device->sizes.blocks << device->sizes.s2b_shift) >> 1); - free_page((long)private->label); - return 0; + free_page ((long) private->label); + rc = 0; + goto out; + fail: + if ( rc ) { + kfree (device->private); + device->private = NULL; + } + out: + return rc; } static int @@ -418,23 +397,6 @@ dasd_diag_examine_error (ccw_req_t * cqr, devstat_t * stat) return dasd_era_fatal; } -static dasd_erp_action_fn_t -dasd_diag_erp_action (ccw_req_t * cqr) -{ - return default_erp_action; -} - -static dasd_erp_postaction_fn_t -dasd_diag_erp_postaction (ccw_req_t * cqr) -{ - if (cqr->function == default_erp_action) - return default_erp_postaction; - printk (KERN_WARNING PRINTK_HEADER - "unknown ERP action %p\n", - cqr->function); - return NULL; -} - static ccw_req_t * dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req) { @@ -459,14 +421,12 @@ dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req) } bhct = 0; for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size > byt_per_blk) - for (size = 0; size < bh->b_size; size += byt_per_blk) - bhct++; - else - bhct++; + if (bh->b_size < byt_per_blk) + BUG(); + bhct += bh->b_size >> (device->sizes.s2b_shift+9); } /* Build the request */ - rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0); + rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0, device); if (!rw_cp) { return NULL; } @@ -474,28 +434,36 @@ dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req) block = req->sector >> device->sizes.s2b_shift; for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size >= byt_per_blk) { - memset (bio, 0, sizeof (diag_bio_t)); - for (size = 0; size < bh->b_size; size += byt_per_blk) { - bio->type = rw_cmd; - bio->block_number = block + 1; - bio->buffer = __pa (bh->b_data + size); - bio++; - block++; - } - } else { - PRINT_WARN ("Cannot fulfill request smaller than block\n"); - ccw_free_request (rw_cp); - return NULL; - } + memset (bio, 0, sizeof (diag_bio_t)); + for (size = 0; size < bh->b_size; size += byt_per_blk) { + bio->type = rw_cmd; + bio->block_number = block + 1; + bio->buffer = __pa (bh->b_data + size); + bio++; + block++; + } } + asm volatile ("STCK %0":"=m" (rw_cp->buildclk)); rw_cp->device = device; - rw_cp->expires = 50 * TOD_SEC; /* 50 seconds */ + rw_cp->expires = 50 * TOD_SEC; /* 50 seconds */ rw_cp->req = req; check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED); return rw_cp; } +static int +dasd_diag_fill_info (dasd_device_t * device, dasd_information_t * info) +{ + int rc = 0; + info->FBA_layout = 1; + info->characteristics_size = sizeof (dasd_diag_characteristics_t); + memcpy (info->characteristics, + &((dasd_diag_private_t *) device->private)->rdc_data, + sizeof (dasd_diag_characteristics_t)); + info->confdata_size = 0; + return rc; +} + static char * dasd_diag_dump_sense (struct dasd_device_t *device, ccw_req_t * req) { @@ -511,21 +479,19 @@ dasd_diag_dump_sense (struct dasd_device_t *device, ccw_req_t * req) return page; } -dasd_discipline_t dasd_diag_discipline = -{ +dasd_discipline_t dasd_diag_discipline = { + owner: THIS_MODULE, name:"DIAG", ebcname:"DIAG", - max_blocks:PAGE_SIZE/sizeof(diag_bio_t), + max_blocks:PAGE_SIZE / sizeof (diag_bio_t), check_characteristics:dasd_diag_check_characteristics, - do_analysis:dasd_diag_do_analysis, fill_geometry:dasd_diag_fill_geometry, start_IO:dasd_start_diag, examine_error:dasd_diag_examine_error, - erp_action:dasd_diag_erp_action, - erp_postaction:dasd_diag_erp_postaction, build_cp_from_req:dasd_diag_build_cp_from_req, dump_sense:dasd_diag_dump_sense, - int_handler:dasd_ext_handler + int_handler:dasd_ext_handler, + fill_info:dasd_diag_fill_info, }; int @@ -534,32 +500,55 @@ dasd_diag_init (void) int rc = 0; if (MACHINE_IS_VM) { printk (KERN_INFO PRINTK_HEADER - "%s discipline initializing\n", dasd_diag_discipline.name); + "%s discipline initializing\n", + dasd_diag_discipline.name); ASCEBC (dasd_diag_discipline.ebcname, 4); ctl_set_bit (0, 9); register_external_interrupt (0x2603, dasd_ext_handler); - dasd_discipline_enq (&dasd_diag_discipline); + dasd_discipline_add (&dasd_diag_discipline); } else { printk (KERN_INFO PRINTK_HEADER - "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name); + "Machine is not VM: %s discipline not initializing\n", + dasd_diag_discipline.name); rc = -EINVAL; } return rc; } void -dasd_diag_cleanup( void ) { - if ( MACHINE_IS_VM ) { - printk ( KERN_INFO PRINTK_HEADER - "%s discipline cleaning up\n", dasd_diag_discipline.name); - dasd_discipline_deq(&dasd_diag_discipline); - unregister_external_interrupt (0x2603, dasd_ext_handler); - ctl_clear_bit (0, 9); - } else { - printk ( KERN_INFO PRINTK_HEADER - "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name); - } +dasd_diag_cleanup (void) +{ + if (MACHINE_IS_VM) { + printk (KERN_INFO PRINTK_HEADER + "%s discipline cleaning up\n", + dasd_diag_discipline.name); + dasd_discipline_del (&dasd_diag_discipline); + unregister_external_interrupt (0x2603, dasd_ext_handler); + ctl_clear_bit (0, 9); + } else { + printk (KERN_INFO PRINTK_HEADER + "Machine is not VM: %s discipline not initializing\n", + dasd_diag_discipline.name); + } } + +#ifdef MODULE +int +init_module (void) +{ + int rc = 0; + rc = dasd_diag_init (); + return rc; +} + +void +cleanup_module (void) +{ + dasd_diag_cleanup (); + return; +} +#endif + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h index dfc532650147..5e94215ce93e 100644 --- a/drivers/s390/block/dasd_diag.h +++ b/drivers/s390/block/dasd_diag.h @@ -29,9 +29,9 @@ typedef struct dasd_diag_characteristics_t { u8 rdev_type; u8 rdev_model; u8 rdev_features; -} __attribute__ ((packed, aligned (4))) +} __attribute__ ((packed, aligned (4))) -dasd_diag_characteristics_t; + dasd_diag_characteristics_t; typedef struct diag_bio_t { u8 type; @@ -40,9 +40,9 @@ typedef struct diag_bio_t { u32 block_number; u32 alet; u32 buffer; -} __attribute__ ((packed, aligned (8))) +} __attribute__ ((packed, aligned (8))) -diag_bio_t; + diag_bio_t; typedef struct diag_init_io_t { u16 dev_nr; @@ -52,9 +52,9 @@ typedef struct diag_init_io_t { u32 start_block; u32 end_block; u32 spare2[6]; -} __attribute__ ((packed, aligned (8))) +} __attribute__ ((packed, aligned (8))) -diag_init_io_t; + diag_init_io_t; typedef struct diag_rw_io_t { u16 dev_nr; @@ -67,9 +67,9 @@ typedef struct diag_rw_io_t { u32 bio_list; u32 interrupt_params; u32 spare3[5]; -} __attribute__ ((packed, aligned (8))) +} __attribute__ ((packed, aligned (8))) -diag_rw_io_t; + diag_rw_io_t; int dasd_diag_init (void); -void dasd_diag_cleanup(void); +void dasd_diag_cleanup (void); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ed2b888cd8b5..844e8b969806 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1,6 +1,7 @@ /* * File...........: linux/drivers/s390/block/dasd_eckd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + Carsten Otte <Cotte@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 @@ -22,27 +23,25 @@ #include <linux/config.h> #include <linux/stddef.h> #include <linux/kernel.h> -#include <asm/debug.h> - #include <linux/slab.h> #include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/blk.h> + +#include <asm/debug.h> #include <asm/ccwcache.h> #include <asm/idals.h> -#include <asm/dasd.h> - #include <asm/ebcdic.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/s390dyn.h> +#include "dasd_int.h" #include "dasd_eckd.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER #endif /* PRINTK_HEADER */ -#define PRINTK_HEADER DASD_NAME"(eckd): " -#undef DASD_CDL // Support compatible disk layout +#define PRINTK_HEADER DASD_NAME"(eckd):" #undef CDL_PRINTK #define ECKD_C0(i) (i->home_bytes) @@ -62,55 +61,39 @@ typedef struct dasd_eckd_private_t { dasd_eckd_characteristics_t rdc_data; dasd_eckd_confdata_t conf_data; -#ifdef DASD_CDL - eckd_count_t count_area[5]; -#else - eckd_count_t count_area; -#endif - ccw_req_t *init_cqr; -#ifdef DASD_CDL - int uses_cdl; -#endif + eckd_count_t count_area[5]; + int uses_cdl; } dasd_eckd_private_t; #ifdef CONFIG_DASD_DYNAMIC static -devreg_t dasd_eckd_known_devices[] = -{ - { - ci: - {hc: - {ctype:0x3990}}, - flag: (DEVREG_MATCH_CU_TYPE | - DEVREG_NO_DEV_INFO| - DEVREG_TYPE_DEVCHARS), - oper_func:dasd_oper_handler - }, +devreg_t dasd_eckd_known_devices[] = { + { + ci: { hc: {ctype:0x3880, dtype: 3390}}, + flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE | + DEVREG_TYPE_DEVCHARS), + oper_func:dasd_oper_handler + }, + { + ci: { hc: {ctype:0x3990}}, + flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS), + oper_func:dasd_oper_handler + }, { - ci: - {hc: - {ctype:0x2105}}, - flag:(DEVREG_MATCH_CU_TYPE | - DEVREG_NO_DEV_INFO| - DEVREG_TYPE_DEVCHARS), - oper_func:dasd_oper_handler - }, + ci: { hc: {ctype:0x2105}}, + flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS), + oper_func:dasd_oper_handler + }, { - ci: - {hc: - {ctype:0x9343}}, - flag:(DEVREG_MATCH_CU_TYPE | - DEVREG_NO_DEV_INFO| - DEVREG_TYPE_DEVCHARS), - oper_func:dasd_oper_handler - } + ci: { hc: {ctype:0x9343}}, + flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS), + oper_func:dasd_oper_handler + } }; #endif -#ifdef DASD_CDL -int sizes_trk0[]={28,148,84}; +int sizes_trk0[] = { 28, 148, 84 }; #define LABEL_SIZE 140 -#endif static inline unsigned int round_up_multiple (unsigned int no, unsigned int mult) @@ -126,8 +109,7 @@ ceil_quot (unsigned int d1, unsigned int d2) } static inline int -bytes_per_record (dasd_eckd_characteristics_t * rdc, - int kl, /* key length */ +bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl, /* key length */ int dl /* data length */ ) { int bpr = 0; @@ -194,8 +176,7 @@ recs_per_track (dasd_eckd_characteristics_t * rdc, 9 + ceil_quot (kl + 6 * kn, 34) + 9 + ceil_quot (dl + 6 * dn, 34)); } else - return 1729 / (10 + - 9 + ceil_quot (dl + 6 * dn, 34)); + return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34)); case 0x9345: dn = ceil_quot (dl + 6, 232) + 1; if (kl) { @@ -204,21 +185,17 @@ recs_per_track (dasd_eckd_characteristics_t * rdc, 7 + ceil_quot (kl + 6 * kn, 34) + ceil_quot (dl + 6 * dn, 34)); } else - return 1420 / (18 + - 7 + ceil_quot (dl + 6 * dn, 34)); + return 1420 / (18 + 7 + ceil_quot (dl + 6 * dn, 34)); } return rpt; } - -static inline void +static inline int define_extent (ccw1_t * de_ccw, DE_eckd_data_t * data, - int trk, - int totrk, - int cmd, - dasd_device_t * device) + int trk, int totrk, int cmd, dasd_device_t * device, ccw_req_t* cqr) { + int rc=0; ch_t geo, beg, end; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; @@ -232,7 +209,8 @@ define_extent (ccw1_t * de_ccw, memset (de_ccw, 0, sizeof (ccw1_t)); de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; de_ccw->count = 16; - set_normalized_cda (de_ccw, __pa (data)); + if (rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device)) + return rc; memset (data, 0, sizeof (DE_eckd_data_t)); switch (cmd) { @@ -259,6 +237,7 @@ define_extent (ccw1_t * de_ccw, case DASD_ECKD_CCW_WRITE_CKD_MT: data->attributes.operation = 0x1; /* format through cache */ break; + case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: case DASD_ECKD_CCW_WRITE_RECORD_ZERO: data->mask.perm = 0x3; @@ -270,46 +249,66 @@ define_extent (ccw1_t * de_ccw, break; } data->attributes.mode = 0x3; - if (private->rdc_data.cu_type == 0x2105 -#ifdef DASD_CDL - && !(private->uses_cdl && trk < 2) -#endif - ) { + if (private->rdc_data.cu_type == 0x2105 + && !(private->uses_cdl && trk < 2) + ) { data->reserved |= 0x40; } data->beg_ext.cyl = beg.cyl; data->beg_ext.head = beg.head; data->end_ext.cyl = end.cyl; data->end_ext.head = end.head; + return rc; } -static inline void +static inline int locate_record (ccw1_t * lo_ccw, LO_eckd_data_t * data, int trk, int rec_on_trk, - int no_rec, - int cmd, - dasd_device_t * device, - int reclen) + int no_rec, int cmd, dasd_device_t * device, int reclen, ccw_req_t* cqr) { + int rc=0; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; - ch_t geo = - {private->rdc_data.no_cyl, - private->rdc_data.trk_per_cyl}; - ch_t seek = - {trk / (geo.head), trk % (geo.head)}; - int sector; + ch_t geo = { private->rdc_data.no_cyl, + private->rdc_data.trk_per_cyl + }; + ch_t seek = { trk / (geo.head), trk % (geo.head) }; + int sector = 0; #ifdef CDL_PRINTK - printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n",trk,rec_on_trk,no_rec,cmd,reclen); + printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n", trk, + rec_on_trk, no_rec, cmd, reclen); #endif memset (lo_ccw, 0, sizeof (ccw1_t)); lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; lo_ccw->count = 16; - set_normalized_cda (lo_ccw, __pa (data)); + if (rc=dasd_set_normalized_cda (lo_ccw, __pa (data), cqr, device)) + return rc; memset (data, 0, sizeof (LO_eckd_data_t)); + if (rec_on_trk) { + switch (private->rdc_data.dev_type) { + case 0x3390:{ + int dn, d; + dn = ceil_quot (reclen + 6, 232); + d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34); + sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; + break; + } + case 0x3380:{ + int d; + d = 7 + ceil_quot (reclen + 12, 32); + sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; + break; + } + case 0x9345: + default: + sector = 0; + } + } + data->sector = sector; + data->count = no_rec; switch (cmd) { case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: data->operation.orientation = 0x3; @@ -360,32 +359,18 @@ locate_record (ccw1_t * lo_ccw, case DASD_ECKD_CCW_READ_COUNT: data->operation.operation = 0x06; break; + case DASD_ECKD_CCW_ERASE: + data->length = reclen; + data->auxiliary.last_bytes_used = 0x1; + data->operation.operation = 0x0b; + break; default: INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd); } - switch (private->rdc_data.dev_type) { - case 0x3390:{ - int dn, d; - dn = ceil_quot (reclen + 6, 232); - d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34); - sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; - break; - } - case 0x3380:{ - int d; - d = 7 + ceil_quot (reclen + 12, 32); - sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; - break; - } - case 0x9345: - default: - sector = 0; - } - data->sector = sector; memcpy (&(data->seek_addr), &seek, sizeof (ch_t)); memcpy (&(data->search_arg), &seek, sizeof (ch_t)); data->search_arg.record = rec_on_trk; - data->count += no_rec; + return rc; } static int @@ -393,12 +378,10 @@ dasd_eckd_id_check (s390_dev_info_t * info) { if (info->sid_data.cu_type == 0x3990 || info->sid_data.cu_type == 0x2105) - if (info->sid_data.dev_type == 0x3390) - return 0; + if (info->sid_data.dev_type == 0x3390) return 0; if (info->sid_data.cu_type == 0x3990 || info->sid_data.cu_type == 0x2105) - if (info->sid_data.dev_type == 0x3380) - return 0; + if (info->sid_data.dev_type == 0x3380) return 0; if (info->sid_data.cu_type == 0x9343) if (info->sid_data.dev_type == 0x9345) return 0; @@ -408,7 +391,7 @@ dasd_eckd_id_check (s390_dev_info_t * info) static int dasd_eckd_check_characteristics (struct dasd_device_t *device) { - int rc = -ENODEV; + int rc = 0; void *conf_data; void *rdc_data; int conf_len; @@ -416,82 +399,89 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device) if (device == NULL) { printk (KERN_WARNING PRINTK_HEADER - "Null device pointer passed to characteristics checker\n"); - return -ENODEV; + "Null device pointer passed to characteristics checker\n"); + return -ENODEV; + } + device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL); + if (device->private == NULL) { + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + rc = -ENOMEM; + goto fail; } - if (device->private != NULL) { - kfree(device->private); - } - device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL); - if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } private = (dasd_eckd_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); rc = read_dev_chars (device->devinfo.irq, &rdc_data, 64); if (rc) { printk (KERN_WARNING PRINTK_HEADER "Read device characteristics returned error %d\n", rc); - return rc; - } + goto fail; + } printk (KERN_INFO PRINTK_HEADER - "%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n", + "%04X on sch %d: %04X/%02X(CU:%04X/%02X) " + "Cyl:%d Head:%d Sec:%d\n", device->devinfo.devno, device->devinfo.irq, private->rdc_data.dev_type, private->rdc_data.dev_model, private->rdc_data.cu_type, private->rdc_data.cu_model.model, private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl, private->rdc_data.sec_per_trk); - rc = 0 ? 0 : read_conf_data (device->devinfo.irq, &conf_data, &conf_len, LPM_ANYPATH); + rc = read_conf_data (device->devinfo.irq, &conf_data, &conf_len, + LPM_ANYPATH); + + if (rc == -EOPNOTSUPP) { + rc = 0; /* this one is ok */ + } if (rc) { - if (rc == -EOPNOTSUPP) - return 0; printk (KERN_WARNING PRINTK_HEADER "Read configuration data returned error %d\n", rc); - return rc; - } - if (conf_len != sizeof (dasd_eckd_confdata_t)) { - printk (KERN_WARNING PRINTK_HEADER - "sizes of configuration data mismatch %d (read) vs %ld (expected)\n", - conf_len, sizeof (dasd_eckd_confdata_t)); - return rc; + goto fail; } - if (conf_data == NULL) { + if (conf_data == NULL) { printk (KERN_WARNING PRINTK_HEADER "No configuration data retrieved\n"); - return -ENOMEM; - } - memcpy (&private->conf_data, conf_data, sizeof (dasd_eckd_confdata_t)); - printk (KERN_INFO PRINTK_HEADER - "%04X on sch %d: %04X/%02X(CU:%04X/%02X): Configuration data read\n", - device->devinfo.devno, device->devinfo.irq, - private->rdc_data.dev_type, private->rdc_data.dev_model, - private->rdc_data.cu_type, private->rdc_data.cu_model.model); - device->sizes.bp_block = 4096; - device->sizes.s2b_shift = 3; - device->sizes.blocks = (private->rdc_data.no_cyl * - private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, - 0, device->sizes.bp_block)); - return 0; + goto out; /* no errror */ + } + if (conf_len != sizeof (dasd_eckd_confdata_t)) { + printk (KERN_WARNING PRINTK_HEADER + "sizes of configuration data mismatch" + "%d (read) vs %ld (expected)\n", + conf_len, sizeof (dasd_eckd_confdata_t)); + goto out; /* no errror */ + } + memcpy (&private->conf_data, conf_data, + sizeof (dasd_eckd_confdata_t)); + printk (KERN_INFO PRINTK_HEADER + "%04X on sch %d: %04X/%02X(CU:%04X/%02X): " + "Configuration data read\n", + device->devinfo.devno, device->devinfo.irq, + private->rdc_data.dev_type, + private->rdc_data.dev_model, + private->rdc_data.cu_type, + private->rdc_data.cu_model.model); + goto out; + fail: + if ( rc ) { + kfree (device->private); + device->private = NULL; + } + out: + return rc; } -#ifdef DASD_CDL static inline int -dasd_eckd_cdl_reclen (dasd_device_t* device,int recid) { - dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; - int byt_per_blk = device->sizes.bp_block; - int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); - if (recid < 3) - return sizes_trk0[recid]; - if (recid < blk_per_trk) - return byt_per_blk; - if (recid < 2*blk_per_trk ) - return LABEL_SIZE; - return byt_per_blk; +dasd_eckd_cdl_reclen (dasd_device_t * device, int recid) +{ + dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; + int byt_per_blk = device->sizes.bp_block; + int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); + if (recid < 3) + return sizes_trk0[recid]; + if (recid < blk_per_trk) + return byt_per_blk; + if (recid < 2 * blk_per_trk) + return LABEL_SIZE; + return byt_per_blk; } -#endif static ccw_req_t * dasd_eckd_init_analysis (struct dasd_device_t *device) @@ -500,76 +490,82 @@ dasd_eckd_init_analysis (struct dasd_device_t *device) ccw1_t *ccw; DE_eckd_data_t *DE_data; LO_eckd_data_t *LO_data; - dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; -#ifdef DASD_CDL - eckd_count_t *count_data = private->count_area; -#else - eckd_count_t *count_data = &(private->count_area); -#endif -#ifdef DASD_CDL - cqr = ccw_alloc_request (dasd_eckd_discipline.name, 8 + 1, - sizeof (DE_eckd_data_t) + - 2*sizeof (LO_eckd_data_t)); -#else - cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, - sizeof (DE_eckd_data_t) + - sizeof (LO_eckd_data_t)); -#endif + dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private; + eckd_count_t *count_data = private->count_area; + + cqr = dasd_alloc_request (dasd_eckd_discipline.name, 8 + 1, + sizeof (DE_eckd_data_t) + + 2 * sizeof (LO_eckd_data_t), + device); if (cqr == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "No memory to allocate initialization request\n"); - return NULL; - } else { - private->init_cqr = cqr; + printk (KERN_WARNING PRINTK_HEADER + "No memory to allocate initialization request\n"); + goto out; } DE_data = cqr->data; LO_data = cqr->data + sizeof (DE_eckd_data_t); ccw = cqr->cpaddr; -#ifdef DASD_CDL - define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device); -#else - define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device); -#endif + if (define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device, cqr)) { + goto clear_cqr; + } ccw->flags |= CCW_FLAG_CC; ccw++; -#ifdef DASD_CDL - locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT, device, 0); -#else - locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); -#endif -#ifdef DASD_CDL + if (locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT, + device, 0, cqr)) { + goto clear_cqr; + } ccw->flags |= CCW_FLAG_CC; ccw++; ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->count = 8; - set_normalized_cda (ccw, __pa (count_data++)); - ccw->flags |= CCW_FLAG_CC; - ccw++; - ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; - ccw->count = 8; - set_normalized_cda (ccw, __pa (count_data++)); - ccw->flags |= CCW_FLAG_CC; - ccw++; - ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; - ccw->count = 8; - set_normalized_cda (ccw, __pa (count_data++)); - ccw->flags |= CCW_FLAG_CC; - ccw++; - ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; - ccw->count = 8; - set_normalized_cda (ccw, __pa (count_data++)); - ccw->flags |= CCW_FLAG_CC; - ccw++; - locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); -#endif - ccw->flags |= CCW_FLAG_CC; - ccw++; - ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; - ccw->count = 8; - set_normalized_cda (ccw, __pa (count_data)); + if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) { + goto clear_cqr; + } + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) { + goto clear_cqr; + } + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) { + goto clear_cqr; + } + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) { + goto clear_cqr; + } + ccw->flags |= CCW_FLAG_CC; + ccw++; + if (locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT, + device, 0, cqr)) { + goto clear_cqr; + } + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + if (dasd_set_normalized_cda (ccw, __pa (count_data), cqr, device)) { + goto clear_cqr; + } cqr->device = device; cqr->retries = 0; cqr->status = CQR_STATUS_FILLED; + dasd_chanq_enq (&device->queue, cqr); + goto out; + clear_cqr: + dasd_free_request (cqr,device); + printk (KERN_WARNING PRINTK_HEADER + "No memory to allocate initialization request\n"); + cqr=NULL; + out: return cqr; } @@ -578,105 +574,91 @@ dasd_eckd_do_analysis (struct dasd_device_t *device) { int sb, rpt; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; - eckd_count_t *count_area = NULL; - char *cdl_msg; -#ifdef DASD_CDL /* BAD HACK SO FIX ME UP */ - int i; - private -> uses_cdl = 1; - - /* Free the cqr and cleanup device->sizes */ - dasd_chanq_deq (&device->queue, private->init_cqr); - ccw_free_request (private->init_cqr); - private->init_cqr = NULL; - memset (&(device->sizes), 0, sizeof (dasd_sizes_t)); - /* Check Track 0 for Compatible Disk Layout */ - for (i = 0; i < 3; i++) { - if ((i < 3) && - ((private->count_area[i].kl != 4) || - (private->count_area[i].dl != - dasd_eckd_cdl_reclen (device,i) - 4))) { - private -> uses_cdl = 0; - break; - } - } - if ( i == 3 ) { - count_area = &private->count_area[4]; - } - if (private->uses_cdl == 0) { - for (i = 0; i < 5; i++) { - if ((private->count_area[i].kl != 0) || - (private->count_area[i].dl != - private->count_area[0].dl)) { - break; - } - } - if ( i == 5 ) { - count_area = &private->count_area[0]; - } - } else { - if (private->count_area[3].record == 1) { - DASD_MESSAGE(KERN_WARNING,device,"%s", - "Trk 0: no records after VTOC!"); - } + eckd_count_t *count_area = NULL; + char *cdl_msg; + int status; + int i; + private->uses_cdl = 1; + status = device->init_cqr->status; + dasd_chanq_deq (&device->queue, device->init_cqr); + dasd_free_request (device->init_cqr, device); + /* Free the cqr and cleanup device->sizes */ + if ( status != CQR_STATUS_DONE ) { + DASD_MESSAGE (KERN_WARNING,device,"%s", + "volume analysis returned fatal error"); + return -EMEDIUMTYPE; } - if (count_area != NULL && /* we found notthing violating our disk layout */ - count_area ->kl == 0) { + /* Check Track 0 for Compatible Disk Layout */ + for (i = 0; i < 3; i++) { + if ((i < 3) && + ((private->count_area[i].kl != 4) || + (private->count_area[i].dl != + dasd_eckd_cdl_reclen (device, i) - 4))) { + private->uses_cdl = 0; + break; + } + } + if (i == 3) { + count_area = &private->count_area[4]; + } + if (private->uses_cdl == 0) { + for (i = 0; i < 5; i++) { + if ((private->count_area[i].kl != 0) || + (private->count_area[i].dl != + private->count_area[0].dl)) { + break; + } + } + if (i == 5) { + count_area = &private->count_area[0]; + } + } else { + if (private->count_area[3].record == 1) { + DASD_MESSAGE (KERN_WARNING, device, "%s", + "Trk 0: no records after VTOC!"); + } + } + if (count_area != NULL && /* we found notthing violating our disk layout */ + count_area->kl == 0) { /* find out blocksize */ switch (count_area->dl) { case 512: - case 1024: - case 2048: - case 4096: - device->sizes.bp_block = count_area->dl; - break; - } - } -#else - dasd_chanq_deq (&device->queue, private->init_cqr); - ccw_free_request (private->init_cqr); - private->init_cqr = NULL; - memset (&(device->sizes), 0, sizeof (dasd_sizes_t)); - switch (private->count_area.dl) { - case 512: - case 1024: - case 2048: - case 4096: - device->sizes.bp_block = private->count_area.dl; - break; + case 1024: + case 2048: + case 4096: + device->sizes.bp_block = count_area->dl; + break; + } + } + if (device->sizes.bp_block == 0) { + DASD_MESSAGE (KERN_WARNING, device, "%s\n", + "Volume has incompatible disk layout"); + return -EMEDIUMTYPE; } -#endif - if ( device->sizes.bp_block == 0 ) { - DASD_MESSAGE(KERN_WARNING, device,"%s\n", - "Volume has incompatible disk layout"); - return -EMEDIUMTYPE; - } device->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */ - device->sizes.pt_block = 2; + device->sizes.pt_block = 2; for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1) device->sizes.s2b_shift++; rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block); - device->sizes.blocks = (private->rdc_data.no_cyl * - private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, - device->sizes.bp_block)); -#ifdef DASD_CDL - cdl_msg = private->uses_cdl?"compatible disk layout":"classic disk layout"; -#else - cdl_msg = "classic disk layout"; -#endif - - DASD_MESSAGE(KERN_INFO,device,"(%dkB blks): %dkB at %dkB/trk %s", - (device->sizes.bp_block >> 10), - (private->rdc_data.no_cyl * - private->rdc_data.trk_per_cyl * - recs_per_track (&private->rdc_data, 0, - device->sizes.bp_block) * - (device->sizes.bp_block >> 9)) >> 1, - (recs_per_track (&private->rdc_data, 0, - device->sizes.bp_block) * - device->sizes.bp_block) >> 10, - cdl_msg); + device->sizes.blocks = (private->rdc_data.no_cyl * + private->rdc_data.trk_per_cyl * + recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block)); + cdl_msg = + private-> + uses_cdl ? "compatible disk layout" : "classic disk layout"; + + DASD_MESSAGE (KERN_INFO, device, "(%dkB blks): %dkB at %dkB/trk %s", + (device->sizes.bp_block >> 10), + (private->rdc_data.no_cyl * + private->rdc_data.trk_per_cyl * + recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block) * + (device->sizes.bp_block >> 9)) >> 1, + (recs_per_track (&private->rdc_data, 0, + device->sizes.bp_block) * + device->sizes.bp_block) >> 10, cdl_msg); return 0; } @@ -690,13 +672,14 @@ dasd_eckd_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo) case 1024: case 2048: case 4096: - break; + geo->sectors = recs_per_track (&(private->rdc_data), + 0, device->sizes.bp_block); + break; default: - return -EINVAL; + break; } geo->cylinders = private->rdc_data.no_cyl; geo->heads = private->rdc_data.trk_per_cyl; - geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block); return rc; } @@ -713,95 +696,89 @@ dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata) ccw1_t *last_ccw = NULL; void *last_data = NULL; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; - int trk = fdata->start_unit; - int bs = fdata->blksize == DASD_FORMAT_DEFAULT_BLOCKSIZE ? 4096 : fdata->blksize; - int flags = fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ? 0 : fdata->intensity; - int rpt = recs_per_track (&(private->rdc_data), 0, bs); - int cyl = trk / private->rdc_data.trk_per_cyl; - int head = trk % private->rdc_data.trk_per_cyl; + int rpt = recs_per_track (&(private->rdc_data), 0, fdata->blksize); + int cyl = fdata->start_unit / private->rdc_data.trk_per_cyl; + int head = fdata->start_unit % private->rdc_data.trk_per_cyl; int wrccws = rpt; int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t); -#ifdef DASD_CDL - int formatCDL=0; -#endif - - if (((fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) && - trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) || - ((fdata->stop_unit != DASD_FORMAT_DEFAULT_STOP_UNIT) && - trk > fdata->stop_unit)) { - DASD_MESSAGE(KERN_INFO, device,"Track %d reached! ending.", trk); + + if (fdata->start_unit >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){ + DASD_MESSAGE (KERN_INFO, device, "Track no %d too big!", fdata->start_unit); + return NULL; + } + if ( fdata->start_unit > fdata->stop_unit) { + DASD_MESSAGE (KERN_INFO, device, "Track %d reached! ending.", + fdata->start_unit); return NULL; } - switch (bs) { + switch (fdata->blksize) { case 512: case 1024: case 2048: case 4096: break; default: - printk (KERN_WARNING PRINTK_HEADER "Invalid blocksize %d...terminating!\n", bs); + printk (KERN_WARNING PRINTK_HEADER + "Invalid blocksize %d...terminating!\n", fdata->blksize); return NULL; } - switch (flags) { + switch (fdata->intensity) { case 0x00: case 0x01: case 0x03: case 0x04: /* make track invalid */ - break; -#ifdef DASD_CDL /* Format compatible disk Layout */ - case 0x08: - case 0x09: - case 0x0b: - case 0x0c: - formatCDL=1; + case 0x08: + case 0x09: + case 0x0b: + case 0x0c: break; -#endif default: - printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n", flags); + printk (KERN_WARNING PRINTK_HEADER + "Invalid flags 0x%x...terminating!\n", fdata->intensity); return NULL; } /* print status line */ if ((private->rdc_data.no_cyl < 20) ? - (trk % private->rdc_data.no_cyl == 0) : - (trk % private->rdc_data.no_cyl == 0 && - (trk / private->rdc_data.no_cyl) % + (fdata->start_unit % private->rdc_data.no_cyl == 0) : + (fdata->start_unit % private->rdc_data.no_cyl == 0 && + (fdata->start_unit / private->rdc_data.no_cyl) % (private->rdc_data.no_cyl / 20))) { - DASD_MESSAGE(KERN_INFO, device, "Format Cylinder: %d Flags: %d\n", - trk / private->rdc_data.trk_per_cyl, - flags); + DASD_MESSAGE (KERN_INFO, device, + "Format Cylinder: %d Flags: %d\n", + fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity); } - if (flags & 0x04) { - rpt = 1; + if ((fdata->intensity & ~0x8) & 0x04) { wrccws = 1; - bs = 8; + rpt = 1; } else { - if (flags & 0x1) { + if (fdata->intensity & 0x1) { wrccws++; datasize += sizeof (eckd_count_t); } - if (flags & 0x2) { + if (fdata->intensity & 0x2) { wrccws++; datasize += sizeof (eckd_home_t); } } - fcp = ccw_alloc_request (dasd_eckd_discipline.name, + fcp = dasd_alloc_request (dasd_eckd_discipline.name, wrccws + 2 + 1, - datasize + rpt * sizeof (eckd_count_t)); + datasize + rpt * sizeof (eckd_count_t), + device ); if (fcp != NULL) { fcp->device = device; - fcp->retries = 2; /* set retry counter to enable ERP */ + fcp->retries = 2; /* set retry counter to enable ERP */ last_data = fcp->data; DE_data = (DE_eckd_data_t *) last_data; last_data = (void *) (DE_data + 1); LO_data = (LO_eckd_data_t *) last_data; last_data = (void *) (LO_data + 1); - if (flags & 0x2) { + if (fdata->intensity & 0x2) { ha_data = (eckd_home_t *) last_data; last_data = (void *) (ha_data + 1); } - if (flags & 0x1) { + if (fdata->intensity & 0x1) { r0_data = (eckd_count_t *) last_data; last_data = (void *) (r0_data + 1); } @@ -809,63 +786,65 @@ dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata) last_ccw = fcp->cpaddr; - switch (flags) { + switch (fdata->intensity & ~0x08) { case 0x03: - case 0x0b: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); + if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, + device, fcp)) { + goto clear_fcp; + } last_ccw->flags |= CCW_FLAG_CC; last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device, device->sizes.bp_block); + if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device, + device->sizes.bp_block, fcp)) { + goto clear_fcp; + } last_ccw->flags |= CCW_FLAG_CC; last_ccw++; break; case 0x01: - case 0x09: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_RECORD_ZERO, device); + if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit, + DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, fcp)) { + goto clear_fcp; + } last_ccw->flags |= CCW_FLAG_CC; last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, device->sizes.bp_block); + if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws, + DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, + device->sizes.bp_block, fcp)) { + goto clear_fcp; + } last_ccw->flags |= CCW_FLAG_CC; last_ccw++; memset (r0_data, 0, sizeof (eckd_count_t)); break; - case 0x00: - case 0x08: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_CKD, device); - last_ccw->flags |= CCW_FLAG_CC; - last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_CKD, device, device->sizes.bp_block); - LO_data->length = bs; - last_ccw->flags |= CCW_FLAG_CC; - last_ccw++; - break; case 0x04: - case 0x0c: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_CKD, device); + fdata->blksize = 8; + case 0x00: + if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit, + DASD_ECKD_CCW_WRITE_CKD, device, fcp)) { + dasd_free_request (fcp, device); + return NULL; + } last_ccw->flags |= CCW_FLAG_CC; last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_CKD, device, 0); - LO_data->length = bs; + if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws, + DASD_ECKD_CCW_WRITE_CKD, device, fdata->blksize, fcp)) { + goto clear_fcp; + } last_ccw->flags |= CCW_FLAG_CC; last_ccw++; break; default: - PRINT_WARN ("Unknown format flags...%d\n", flags); + PRINT_WARN ("Unknown format flags...%d\n", fdata->intensity); return NULL; } - if (flags & 0x02) { - PRINT_WARN ("Unsupported format flag...%d\n", flags); + if (fdata->intensity & 0x02) { + PRINT_WARN ("Unsupported format flag...%d\n", fdata->intensity); return NULL; } - if (flags & 0x01) { /* write record zero */ + if (fdata->intensity & 0x01) { /* write record zero */ r0_data->cyl = cyl; r0_data->head = head; r0_data->record = 0; @@ -874,49 +853,73 @@ dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata) last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO; last_ccw->count = 8; last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI; - set_normalized_cda (last_ccw, __pa (r0_data)); + if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) { + goto clear_fcp; + } last_ccw++; } - /* write remaining records */ - for (i = 0; i < rpt; i++) { - memset (ct_data + i, 0, sizeof (eckd_count_t)); - (ct_data + i)->cyl = cyl; - (ct_data + i)->head = head; - (ct_data + i)->record = i + 1; - (ct_data + i)->kl = 0; -#ifdef DASD_CDL - if (formatCDL) { - // special handling when formatting CDL - switch (trk) { - case 0: - if (i<3) { - (ct_data + i)->kl = 4; - (ct_data + i)->dl = sizes_trk0[i]-4; - } else - (ct_data + i)->dl = bs; - break; - case 1: - (ct_data + i)->kl = 44; - (ct_data + i)->dl = LABEL_SIZE-44; - break; - default: - (ct_data + i)->dl = bs; - break; - } - } - else -#endif - (ct_data + i)->dl = bs; + if ((fdata->intensity & ~0x08) & 0x04) { /* erase track */ + memset (ct_data, 0, sizeof (eckd_count_t)); + ct_data->cyl = cyl; + ct_data->head = head; + ct_data->record = 1; + ct_data->kl = 0; + ct_data->dl = 0; last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; - last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI; last_ccw->count = 8; - set_normalized_cda (last_ccw, __pa (ct_data + i)); + last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI; + if (dasd_set_normalized_cda (last_ccw, __pa (ct_data), fcp, device)) { + goto clear_fcp; + } last_ccw++; + } else { /* write remaining records */ + for (i = 0; i < rpt; i++) { + memset (ct_data + i, 0, sizeof (eckd_count_t)); + (ct_data + i)->cyl = cyl; + (ct_data + i)->head = head; + (ct_data + i)->record = i + 1; + (ct_data + i)->kl = 0; + if (fdata->intensity & 0x08) { + // special handling when formatting CDL + switch (fdata->start_unit) { + case 0: + if (i < 3) { + (ct_data + i)->kl = 4; + + (ct_data + i)->dl = + sizes_trk0[i] - 4; + } else + (ct_data + i)->dl = fdata->blksize; + break; + case 1: + (ct_data + i)->kl = 44; + (ct_data + i)->dl = LABEL_SIZE - 44; + break; + default: + (ct_data + i)->dl = fdata->blksize; + break; + } + } else + (ct_data + i)->dl = fdata->blksize; + last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; + last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI; + last_ccw->count = 8; + if (dasd_set_normalized_cda (last_ccw, + __pa (ct_data + i), fcp, device)) { + goto clear_fcp; + } + last_ccw++; + } } (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC); fcp->device = device; fcp->status = CQR_STATUS_FILLED; } + goto out; + clear_fcp: + dasd_free_request (fcp, device); + fcp=NULL; + out: return fcp; } @@ -927,7 +930,7 @@ dasd_eckd_examine_error (ccw_req_t * cqr, devstat_t * stat) if (stat->cstat == 0x00 && stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; + return dasd_era_none; switch (device->devinfo.sid_data.cu_type) { case 0x3990: @@ -946,56 +949,56 @@ static dasd_erp_action_fn_t dasd_eckd_erp_action (ccw_req_t * cqr) { dasd_device_t *device = (dasd_device_t *) cqr->device; - + switch (device->devinfo.sid_data.cu_type) { case 0x3990: case 0x2105: return dasd_3990_erp_action; case 0x9343: - /* Return dasd_9343_erp_action; */ + /* Return dasd_9343_erp_action; */ default: - return default_erp_action; + return dasd_default_erp_action; } } static dasd_erp_postaction_fn_t dasd_eckd_erp_postaction (ccw_req_t * cqr) { - return default_erp_postaction; + return dasd_default_erp_postaction; } -#ifdef DASD_CDL inline unsigned char -dasd_eckd_cdl_cmd(dasd_device_t *device,int recid,int cmd) { - dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; - int byt_per_blk = device->sizes.bp_block; - int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); - switch (cmd) { - case READ: - if (recid < 3) - return DASD_ECKD_CCW_READ_KD_MT; - if (recid < blk_per_trk) - return DASD_ECKD_CCW_READ_MT; - if (recid < 2*blk_per_trk) - return DASD_ECKD_CCW_READ_KD_MT; - return DASD_ECKD_CCW_READ_MT; - break; - case WRITE: - if (recid < 3) - return DASD_ECKD_CCW_WRITE_KD_MT; - if (recid < blk_per_trk) - return DASD_ECKD_CCW_WRITE_MT; - if (recid < 2*blk_per_trk) - return DASD_ECKD_CCW_WRITE_KD_MT; - return DASD_ECKD_CCW_WRITE_MT; - break; - default: - BUG(); - } - return 0; // never executed +dasd_eckd_cdl_cmd (dasd_device_t * device, int recid, int cmd) +{ + dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; + int byt_per_blk = device->sizes.bp_block; + int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); + switch (cmd) { + case READ: + if (recid < 3) + return DASD_ECKD_CCW_READ_KD_MT; + if (recid < blk_per_trk) + return DASD_ECKD_CCW_READ_MT; + if (recid < 2 * blk_per_trk) + return DASD_ECKD_CCW_READ_KD_MT; + return DASD_ECKD_CCW_READ_MT; + break; + case WRITE: + if (recid < 3) + return DASD_ECKD_CCW_WRITE_KD_MT; + if (recid < blk_per_trk) + return DASD_ECKD_CCW_WRITE_MT; + if (recid < 2 * blk_per_trk) + return DASD_ECKD_CCW_WRITE_KD_MT; + return DASD_ECKD_CCW_WRITE_MT; + break; + default: + BUG (); + } + return 0; // never executed } -#endif + static ccw_req_t * dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req) @@ -1014,11 +1017,9 @@ dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req) int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); int btrk = (req->sector >> shift) / blk_per_trk; int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk; -#ifdef DASD_CDL - int recid = req->sector >> shift; - int locate4k_set=0; - int nlocs=0; -#endif + int recid = req->sector >> shift; + int locate4k_set = 0; + int nlocs = 0; if (req->cmd == READ) { rw_cmd = DASD_ECKD_CCW_READ_MT; @@ -1032,142 +1033,78 @@ dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req) /* count bhs to prevent errors, when bh smaller than block */ bhct = 0; for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size > byt_per_blk) - for (size = 0; size < bh->b_size; size += byt_per_blk) - bhct++; - else - bhct++; + if (bh->b_size < byt_per_blk) + BUG(); + bhct+= bh->b_size >> (device->sizes.s2b_shift+9); } -#ifndef DASD_CDL - rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, - 2 + bhct + 1, - sizeof (DE_eckd_data_t) + - sizeof (LO_eckd_data_t)); -#else - if (btrk<2 && private->uses_cdl) { - nlocs+= 2*blk_per_trk-recid; - if (etrk<2) - nlocs-=2*blk_per_trk-((req->sector + req->nr_sectors - 1) >> shift); - } - rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, + if (btrk < 2 && private->uses_cdl) { + if (etrk < 2) + nlocs = bhct; + else + nlocs = 2 * blk_per_trk - recid; + } + rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 2 + nlocs + bhct + 1, - sizeof (DE_eckd_data_t) + - (1+nlocs)*sizeof (LO_eckd_data_t)); -#endif + sizeof (DE_eckd_data_t) + (1 + + nlocs) * + sizeof (LO_eckd_data_t), + device); if (!rw_cp) { return NULL; } DE_data = rw_cp->data; LO_data = rw_cp->data + sizeof (DE_eckd_data_t); ccw = rw_cp->cpaddr; - define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device); - ccw->flags |= CCW_FLAG_CC; -#ifndef DASD_CDL - ccw++; - locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1, - req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block); + if (define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device, rw_cp)) { + goto clear_rw_cp; + } ccw->flags |= CCW_FLAG_CC; -#endif for (bh = req->bh; bh != NULL;) { - if (bh->b_size > byt_per_blk) { - for (size = 0; size < bh->b_size; size += byt_per_blk) { -#ifdef DASD_CDL - if (!locate4k_set) { - // we need to chain a locate record before our rw-ccw - ccw++; - if ((recid/blk_per_trk)<2 && private->uses_cdl) { + for (size = 0; size < bh->b_size; size += byt_per_blk) { + if (!locate4k_set) { + // we need to chain a locate record before our rw-ccw + ccw++; + if ((recid / blk_per_trk) < 2 + && private->uses_cdl) { /* Do a locate record for our special blocks */ - locate_record (ccw, LO_data++, recid/blk_per_trk, - recid % blk_per_trk + 1, 1, - dasd_eckd_cdl_cmd(device,recid,req->cmd), - device, - dasd_eckd_cdl_reclen(device,recid)); - } else { - // Do a locate record for standard blocks */ - locate_record (ccw, LO_data++, recid/blk_per_trk, + int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd); + if (locate_record (ccw, + LO_data++, + recid / blk_per_trk, recid % blk_per_trk + 1, - (((req->sector + req->nr_sectors) >> shift)-recid), - rw_cmd,device, device->sizes.bp_block); - locate4k_set=1; - } - ccw->flags |= CCW_FLAG_CC; - } -#endif - ccw++; -#ifndef DASD_CDL - ccw->flags |= CCW_FLAG_CC; - ccw->cmd_code= rw_cmd; - ccw->count = bh->b_size; -#else - ccw->flags |= CCW_FLAG_CC; - ccw->cmd_code=locate4k_set?rw_cmd: - dasd_eckd_cdl_cmd(device,recid,req->cmd); - ccw->count =locate4k_set?bh->b_size: - dasd_eckd_cdl_reclen(device,recid); -#endif - set_normalized_cda (ccw, __pa (bh->b_data)); - size += bh->b_size; - bh = bh->b_reqnext; -#ifdef DASD_CDL - recid++; -#endif - } - bh = bh->b_reqnext; - } else { /* group N bhs to fit into byt_per_blk */ - for (size = 0; bh != NULL && size < byt_per_blk;) { -#ifdef DASD_CDL - if (!locate4k_set) { - // we need to chain a locate record before our rw-ccw - ccw++; - if ((recid/blk_per_trk)<2 && private->uses_cdl) { - /* Do a locate record for our special blocks */ - locate_record (ccw, LO_data++, recid/blk_per_trk, - recid % blk_per_trk + 1, 1, - dasd_eckd_cdl_cmd(device,recid,req->cmd), - device, - dasd_eckd_cdl_reclen(device,recid)); - } else { + 1, cmd, device, + dasd_eckd_cdl_reclen(device, recid), rw_cp)) { + goto clear_rw_cp; + } + } else { // Do a locate record for standard blocks */ - locate_record (ccw, LO_data++, recid/blk_per_trk, - recid % blk_per_trk + 1, - (((req->sector + req->nr_sectors) >> shift)-recid), - rw_cmd,device, device->sizes.bp_block); - locate4k_set=1; - } - ccw->flags |= CCW_FLAG_CC; + if (locate_record (ccw, + LO_data++, + recid /blk_per_trk, + recid %blk_per_trk + 1, + (((req->sector + + req->nr_sectors) >> + shift) - recid), + rw_cmd, device, + device->sizes.bp_block, rw_cp)) { + goto clear_rw_cp; + } + locate4k_set = 1; } -#endif - ccw++; -#ifndef DASD_CDL - ccw->flags |= CCW_FLAG_DC; - ccw->cmd_code= rw_cmd; - ccw->count = bh->b_size; -#else - ccw->flags |= locate4k_set?CCW_FLAG_DC:CCW_FLAG_CC; - ccw->cmd_code=locate4k_set?rw_cmd: - dasd_eckd_cdl_cmd(device,recid,req->cmd); - ccw->count =locate4k_set?bh->b_size: - dasd_eckd_cdl_reclen(device,recid); -#endif - set_normalized_cda (ccw, __pa (bh->b_data)); - size += bh->b_size; - bh = bh->b_reqnext; -#ifdef DASD_CDL - recid++; -#endif - } - if (size != byt_per_blk) { - PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", - size, - byt_per_blk, - req->nr_sectors); - - ccw_free_request (rw_cp); - return NULL; - } - ccw->flags &= ~CCW_FLAG_DC; - ccw->flags |= CCW_FLAG_CC; - } + ccw->flags |= CCW_FLAG_CC; + } + ccw++; + ccw->flags |= CCW_FLAG_CC; + ccw->cmd_code = locate4k_set ? rw_cmd : + dasd_eckd_cdl_cmd (device, recid, req->cmd); + ccw->count = locate4k_set ? byt_per_blk : + dasd_eckd_cdl_reclen (device, recid); + if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) { + goto clear_rw_cp; + } + recid++; + } + bh = bh->b_reqnext; } ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC); rw_cp->device = device; @@ -1176,11 +1113,15 @@ dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req) rw_cp->lpm = LPM_ANYPATH; rw_cp->retries = 2; asm volatile ("STCK %0":"=m" (rw_cp->buildclk)); - check_then_set (&rw_cp->status, - CQR_STATUS_EMPTY, - CQR_STATUS_FILLED); + check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED); + goto out; + clear_rw_cp: + dasd_free_request (rw_cp, device); + rw_cp=NULL; + out: return rw_cp; } + #if 0 int dasd_eckd_cleanup_request (ccw_req_t * cqr) @@ -1197,7 +1138,8 @@ dasd_eckd_cleanup_request (ccw_req_t * cqr) ccw->flags |= CCW_FLAG_CC; ccw->cmd_code = rw_cmd; ccw->count = byt_per_blk; - set_normalized_cda (ccw, __pa (bh->b_data + size)); + set_normalized_cda (ccw, + __pa (bh->b_data + size)); } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ @@ -1218,7 +1160,8 @@ dasd_eckd_cleanup_request (ccw_req_t * cqr) ccw_req_t * dasd_eckd_reserve (struct dasd_device_t * device) { - ccw_req_t *cqr = ccw_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0); + ccw_req_t *cqr = + dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device); if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -1234,7 +1177,8 @@ dasd_eckd_reserve (struct dasd_device_t * device) ccw_req_t * dasd_eckd_release (struct dasd_device_t * device) { - ccw_req_t *cqr = ccw_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0); + ccw_req_t *cqr = + dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device); if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -1254,67 +1198,91 @@ dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd) ccw1_t *cp; cp = cqr->cpaddr; - do { + do { if (cp->cmd_code == cmd) return cp; if (cp->cmd_code == CCW_CMD_TIC) { - cp = (ccw1_t *)cp->cda; - continue; - } - if ( cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC) ) { - cp ++; - continue; + cp = (ccw1_t *) (long) cp->cda; + continue; } - break; - } while ( 1 ); - return NULL; + if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) { + cp++; + continue; + } + break; + } while (1); + return NULL; } -ccw_req_t * -dasd_eckd_merge_cp ( dasd_device_t *device ) +static ccw_req_t * +dasd_eckd_merge_cp (dasd_device_t * device) { - return NULL; + return NULL; } -static char * -dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t * req) +static int +dasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info) +{ + int rc = 0; + info->label_block = 2; + if (((dasd_eckd_private_t *) device->private)->uses_cdl) + info->FBA_layout = 0; + else + info->FBA_layout = 1; + info->characteristics_size = sizeof (dasd_eckd_characteristics_t); + memcpy (info->characteristics, + &((dasd_eckd_private_t *) device->private)->rdc_data, + sizeof (dasd_eckd_characteristics_t)); + info->confdata_size = sizeof (dasd_eckd_confdata_t); + memcpy (info->configuration_data, + &((dasd_eckd_private_t *) device->private)->conf_data, + sizeof (dasd_eckd_confdata_t)); + return rc; +} + +static char* +dasd_eckd_dump_sense (struct dasd_device_t *device, + ccw_req_t *req) { + char *page = (char *) get_free_page (GFP_ATOMIC); devstat_t *stat = &device->dev_status; char *sense = stat->ii.sense.data; int len, sl, sct; if (page == NULL) { + printk (KERN_ERR PRINTK_HEADER + "No memory to dump sense data\n"); return NULL; } - len = sprintf (page, KERN_WARNING PRINTK_HEADER + + len = sprintf (page, KERN_ERR PRINTK_HEADER "device %04X on irq %d: I/O status report:\n", device->devinfo.devno, device->devinfo.irq); - len += sprintf (page + len, KERN_WARNING PRINTK_HEADER + len += sprintf (page + len, KERN_ERR PRINTK_HEADER "in req: %p CS: 0x%02X DS: 0x%02X\n", req, stat->cstat, stat->dstat); - len += sprintf (page + len, KERN_WARNING PRINTK_HEADER - "Failing CCW: %p\n", (void *) stat->cpa); - { - ccw1_t *act = req -> cpaddr; - int i = req -> cplength; - do { -#ifdef ERP_DEBUB - printk ( KERN_INFO "CCW %p: %08X %08X\n", - act,((int*)act)[0],((int*)act)[1]); - printk ( KERN_INFO "DAT: %08X %08X %08X %08X\n", - ((int*)act->cda)[0],((int*)act->cda)[1], - ((int*)act->cda)[2],((int*)act->cda)[3]); -#endif /* ERP_DEBUG */ - act ++; - } while ( --i ); - } + len += sprintf (page + len, KERN_ERR PRINTK_HEADER + "Failing CCW: %p\n", (void *) (long) stat->cpa); + { + ccw1_t *act = req->cpaddr; + int i = req->cplength; + do { +#ifdef ERP_DEBUG + printk (KERN_ERR "CCW %p: %08X %08X\n", + act, ((int *) act)[0], ((int *) act)[1]); + printk (KERN_ERR "DAT: %08X %08X %08X %08X\n", + ((int *) act->cda)[0], ((int *) act->cda)[1], + ((int *) act->cda)[2], ((int *) act->cda)[3]); +#endif /* ERP_DEBUG */ + act++; + } while (--i); + } if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) { for (sl = 0; sl < 4; sl++) { - len += sprintf (page + len, KERN_WARNING PRINTK_HEADER + len += sprintf (page + len, KERN_ERR PRINTK_HEADER "Sense(hex) %2d-%2d:", - (8 * sl), - ((8 * sl) + 7)); + (8 * sl), ((8 * sl) + 7)); for (sct = 0; sct < 8; sct++) { len += sprintf (page + len, " %02x", @@ -1325,22 +1293,29 @@ dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t * req) if (sense[27] & DASD_SENSE_BIT_0) { /* 24 Byte Sense Data */ - len += sprintf (page + len, KERN_WARNING PRINTK_HEADER - "24 Byte: %x MSG %x, %s MSGb to SYSOP\n", + len += sprintf (page + len, KERN_ERR PRINTK_HEADER + "24 Byte: %x MSG %x, %s MSGb to SYSOP\n", sense[7] >> 4, sense[7] & 0x0f, sense[1] & 0x10 ? "" : "no"); } else { /* 32 Byte Sense Data */ - len += sprintf (page + len, KERN_WARNING PRINTK_HEADER - "32 Byte: Format: %x Exception class %x\n", + len += sprintf (page + len, KERN_ERR PRINTK_HEADER + "32 Byte: Format: %x Exception class %x\n", sense[6] & 0x0f, sense[22] >> 4); } } - return page; + + printk ("Sense data:\n%s", + page); + + free_page ((unsigned long) page); + + return NULL; } -dasd_discipline_t dasd_eckd_discipline = -{ + +dasd_discipline_t dasd_eckd_discipline = { + owner: THIS_MODULE, name:"ECKD", ebcname:"ECKD", max_blocks:255, @@ -1350,6 +1325,7 @@ dasd_discipline_t dasd_eckd_discipline = do_analysis:dasd_eckd_do_analysis, fill_geometry:dasd_eckd_fill_geometry, start_IO:dasd_start_IO, + term_IO:dasd_term_IO, format_device:dasd_eckd_format_device, examine_error:dasd_eckd_examine_error, erp_action:dasd_eckd_erp_action, @@ -1359,7 +1335,8 @@ dasd_discipline_t dasd_eckd_discipline = int_handler:dasd_int_handler, reserve:dasd_eckd_reserve, release:dasd_eckd_release, - merge_cp:dasd_eckd_merge_cp + merge_cp:dasd_eckd_merge_cp, + fill_info:dasd_eckd_fill_info, }; int @@ -1369,41 +1346,63 @@ dasd_eckd_init (void) printk (KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_eckd_discipline.name); ASCEBC (dasd_eckd_discipline.ebcname, 4); - dasd_discipline_enq (&dasd_eckd_discipline); + dasd_discipline_add (&dasd_eckd_discipline); #ifdef CONFIG_DASD_DYNAMIC - { - int i; - for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) { - printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x\n", - dasd_eckd_known_devices[i].ci.hc.ctype, - dasd_eckd_known_devices[i].ci.hc.cmode); - s390_device_register (&dasd_eckd_known_devices[i]); - } - } + { + int i; + for (i = 0; + i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); + i++) { + printk (KERN_INFO PRINTK_HEADER + "We are interested in: CU %04X/%02x\n", + dasd_eckd_known_devices[i].ci.hc.ctype, + dasd_eckd_known_devices[i].ci.hc.cmode); + s390_device_register (&dasd_eckd_known_devices[i]); + } + } #endif /* CONFIG_DASD_DYNAMIC */ return rc; } void -dasd_eckd_cleanup( void ) { - printk ( KERN_INFO PRINTK_HEADER - "%s discipline cleaning up\n", dasd_eckd_discipline.name); +dasd_eckd_cleanup (void) +{ + printk (KERN_INFO PRINTK_HEADER + "%s discipline cleaning up\n", dasd_eckd_discipline.name); #ifdef CONFIG_DASD_DYNAMIC - { - int i; - for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) { - printk (KERN_INFO PRINTK_HEADER - "We were interested in: CU %04X/%02x\n", - dasd_eckd_known_devices[i].ci.hc.ctype, - dasd_eckd_known_devices[i].ci.hc.cmode); - s390_device_unregister(&dasd_eckd_known_devices[i]); + { + int i; + for (i = 0; + i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); + i++) { + printk (KERN_INFO PRINTK_HEADER + "We were interested in: CU %04X/%02x\n", + dasd_eckd_known_devices[i].ci.hc.ctype, + dasd_eckd_known_devices[i].ci.hc.cmode); + s390_device_unregister (&dasd_eckd_known_devices[i]); + } } - } -#endif /* CONFIG_DASD_DYNAMIC */ - dasd_discipline_deq(&dasd_eckd_discipline); +#endif /* CONFIG_DASD_DYNAMIC */ + dasd_discipline_del (&dasd_eckd_discipline); } +#ifdef MODULE +int +init_module (void) +{ + int rc = 0; + rc = dasd_eckd_init (); + return rc; +} + +void +cleanup_module (void) +{ + dasd_eckd_cleanup (); + return; +} +#endif + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index cc06fc974d1e..b2b564104d4e 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -10,6 +10,7 @@ #define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a #define DASD_ECKD_CCW_WRITE_KD 0x0d #define DASD_ECKD_CCW_READ_KD 0x0e +#define DASD_ECKD_CCW_ERASE 0x11 #define DASD_ECKD_CCW_READ_COUNT 0x12 #define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 #define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 @@ -26,52 +27,51 @@ #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d #define DASD_ECKD_CCW_RESERVE 0xB4 - -typedef -struct eckd_count_t { +typedef + struct eckd_count_t { __u16 cyl; __u16 head; __u8 record; __u8 kl; __u16 dl; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -eckd_count_t; + eckd_count_t; typedef -struct ch_t { + struct ch_t { __u16 cyl; __u16 head; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -ch_t; + ch_t; typedef -struct chs_t { + struct chs_t { __u16 cyl; __u16 head; __u32 sector; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -chs_t; + chs_t; typedef -struct chr_t { + struct chr_t { __u16 cyl; __u16 head; __u8 record; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -chr_t; + chr_t; typedef -struct geom_t { + struct geom_t { __u16 cyl; __u16 head; __u32 sector; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -geom_t; + geom_t; typedef struct eckd_home_t { __u8 skip_control[14]; @@ -82,12 +82,12 @@ typedef struct eckd_home_t { __u8 reserved; __u8 key_length; __u8 reserved2[2]; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -eckd_home_t; + eckd_home_t; typedef -struct DE_eckd_data_t { + struct DE_eckd_data_t { struct { unsigned char perm:2; /* Permissions on this extent */ unsigned char reserved:1; @@ -108,12 +108,12 @@ struct DE_eckd_data_t { __u8 reserved; ch_t beg_ext; ch_t end_ext; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -DE_eckd_data_t; + DE_eckd_data_t; typedef -struct LO_eckd_data_t { + struct LO_eckd_data_t { struct { unsigned char orientation:2; unsigned char operation:6; @@ -129,12 +129,12 @@ struct LO_eckd_data_t { chr_t search_arg; __u8 sector; __u16 length; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -LO_eckd_data_t; + LO_eckd_data_t; typedef -struct dasd_eckd_characteristics_t { + struct dasd_eckd_characteristics_t { __u16 cu_type; struct { unsigned char support:2; @@ -204,9 +204,9 @@ struct dasd_eckd_characteristics_t { __u8 factor8; __u8 reserved2[3]; __u8 reserved3[10]; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -dasd_eckd_characteristics_t; + dasd_eckd_characteristics_t; typedef struct dasd_eckd_confdata_t { struct { @@ -323,10 +323,10 @@ typedef struct dasd_eckd_confdata_t { __u8 log_dev_address; unsigned char reserved2[12]; } __attribute__ ((packed)) neq; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -dasd_eckd_confdata_t; + dasd_eckd_confdata_t; int dasd_eckd_init (void); -void dasd_eckd_cleanup(void); +void dasd_eckd_cleanup (void); #endif /* DASD_ECKD_H */ diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index a94017a289a5..d55de1aad2a9 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -15,16 +15,18 @@ #include <linux/slab.h> #include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/blk.h> + #include <asm/ccwcache.h> #include <asm/idals.h> -#include <asm/dasd.h> - #include <asm/ebcdic.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/s390dyn.h> +#include "dasd_int.h" #include "dasd_fba.h" +#include "dasd_3370_erp.h" +#include "dasd_9336_erp.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER @@ -39,44 +41,38 @@ dasd_discipline_t dasd_fba_discipline; typedef struct -dasd_fba_private_t { + dasd_fba_private_t { dasd_fba_characteristics_t rdc_data; } dasd_fba_private_t; #ifdef CONFIG_DASD_DYNAMIC static -devreg_t dasd_fba_known_devices[] = -{ +devreg_t dasd_fba_known_devices[] = { { - ci: - {hc: - {ctype:0x6310, - dtype:0x9336}}, - flag:(DEVREG_MATCH_CU_TYPE | - DEVREG_MATCH_DEV_TYPE| - DEVREG_TYPE_DEVCHARS), - oper_func:dasd_oper_handler - }, + ci: { hc: {ctype:0x6310, dtype:0x9336}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS), + oper_func:dasd_oper_handler + }, { - ci: - {hc: - {ctype:0x3880, - dtype:0x3370}}, - flag:(DEVREG_MATCH_CU_TYPE | - DEVREG_MATCH_DEV_TYPE| - DEVREG_TYPE_DEVCHARS), - oper_func:dasd_oper_handler - } + ci: { hc: {ctype:0x3880, dtype:0x3370}}, + flag:(DEVREG_MATCH_CU_TYPE | + DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS), + oper_func:dasd_oper_handler + } }; #endif -static inline void +static inline int define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw, - int blksize, int beg, int nr) + int blksize, int beg, int nr, ccw_req_t* cqr, + dasd_device_t* device) { + int rc=0; memset (DE_data, 0, sizeof (DE_fba_data_t)); ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT; ccw->count = 16; - set_normalized_cda (ccw, __pa (DE_data)); + if (rc=dasd_set_normalized_cda (ccw, __pa (DE_data), cqr, device)) + return rc; if (rw == WRITE) (DE_data->mask).perm = 0x0; else if (rw == READ) @@ -86,16 +82,17 @@ define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw, DE_data->blk_size = blksize; DE_data->ext_loc = beg; DE_data->ext_end = nr - 1; + return rc; } static inline void locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr, - int block_ct) + int block_ct, ccw_req_t* cqr, dasd_device_t* device) { memset (LO_data, 0, sizeof (LO_fba_data_t)); ccw->cmd_code = DASD_FBA_CCW_LOCATE; ccw->count = 8; - set_normalized_cda (ccw, __pa (LO_data)); + dasd_set_normalized_cda (ccw, __pa (LO_data), cqr, device); if (rw == WRITE) LO_data->operation.cmd = 0x5; else if (rw == READ) @@ -109,9 +106,9 @@ locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr, static int dasd_fba_id_check (s390_dev_info_t * info) { - if (info->sid_data.cu_type == 0x3880) - if (info->sid_data.dev_type == 0x3370) - return 0; + if (info->sid_data.cu_type == 0x3880) + if (info->sid_data.dev_type == 0x3370) + return 0; if (info->sid_data.cu_type == 0x6310) if (info->sid_data.dev_type == 0x9336) return 0; @@ -127,37 +124,43 @@ dasd_fba_check_characteristics (struct dasd_device_t *device) if (device == NULL) { printk (KERN_WARNING PRINTK_HEADER - "Null device pointer passed to characteristics checker\n"); - return -ENODEV; + "Null device pointer passed to characteristics checker\n"); + return -ENODEV; } - if ( device->private != NULL ) { - kfree(device->private); - } - device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL); + device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL); if (device->private == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; + printk (KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + rc = -ENOMEM; + goto fail; } private = (dasd_fba_private_t *) device->private; rdc_data = (void *) &(private->rdc_data); rc = read_dev_chars (device->devinfo.irq, &rdc_data, 32); if (rc) { - printk (KERN_WARNING PRINTK_HEADER - "Read device characteristics returned error %d\n", rc); - kfree(private); - device->private=NULL; - return rc; + printk (KERN_WARNING PRINTK_HEADER + "Read device characteristics returned error %d\n", rc); + goto fail; } printk (KERN_INFO PRINTK_HEADER "%04X on sch %d: %04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)\n", device->devinfo.devno, device->devinfo.irq, - device->devinfo.sid_data.dev_type, device->devinfo.sid_data.dev_model, - device->devinfo.sid_data.cu_type, device->devinfo.sid_data.cu_model, + device->devinfo.sid_data.dev_type, + device->devinfo.sid_data.dev_model, + device->devinfo.sid_data.cu_type, + device->devinfo.sid_data.cu_model, (private->rdc_data.blk_bdsa * (private->rdc_data.blk_size >> 9)) >> 11, private->rdc_data.blk_size); - return 0; + goto out; + fail: + if ( rc ) { + kfree(device->private); + device->private = NULL; + } + + out: + return rc; } static int @@ -187,7 +190,7 @@ dasd_fba_do_analysis (struct dasd_device_t *device) device->sizes.s2b_shift++; device->sizes.blocks = (private->rdc_data.blk_bdsa); - device->sizes.pt_block = 1; + device->sizes.pt_block = 1; return rc; } @@ -221,7 +224,7 @@ dasd_fba_examine_error (ccw_req_t * cqr, devstat_t * stat) dasd_device_t *device = (dasd_device_t *) cqr->device; if (stat->cstat == 0x00 && stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; + return dasd_era_none; switch (device->devinfo.sid_data.dev_model) { case 0x3370: @@ -236,17 +239,16 @@ dasd_fba_examine_error (ccw_req_t * cqr, devstat_t * stat) static dasd_erp_action_fn_t dasd_fba_erp_action (ccw_req_t * cqr) { - return default_erp_action; + return dasd_default_erp_action; } static dasd_erp_postaction_fn_t dasd_fba_erp_postaction (ccw_req_t * cqr) { - if (cqr->function == default_erp_action) - return default_erp_postaction; + if (cqr->function == dasd_default_erp_action) + return dasd_default_erp_postaction; printk (KERN_WARNING PRINTK_HEADER - "unknown ERP action %p\n", - cqr->function); + "unknown ERP action %p\n", cqr->function); return NULL; } @@ -255,7 +257,7 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req) { ccw_req_t *rw_cp = NULL; int rw_cmd; - int bhct, i; + int bhct, i = 0; long size; ccw1_t *ccw; DE_fba_data_t *DE_data; @@ -263,7 +265,7 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req) struct buffer_head *bh; dasd_fba_private_t *private = (dasd_fba_private_t *) device->private; int byt_per_blk = device->sizes.bp_block; - + if (req->cmd == READ) { rw_cmd = DASD_FBA_CCW_READ; } else if (req->cmd == WRITE) { @@ -273,20 +275,30 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req) return NULL; } /* Build the request */ - /* count bhs to prevent errors, when bh smaller than block */ + /* count hs to prevent errors, when bh smaller than block */ + bh = req -> bh; bhct = 0; - for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size > byt_per_blk) - for (size = 0; size < bh->b_size; size += byt_per_blk) - bhct++; - else - bhct++; - } - - rw_cp = dasd_alloc_request (dasd_fba_discipline.name, - 1 + 2*bhct, - sizeof (DE_fba_data_t) + - bhct*sizeof (LO_fba_data_t)); + while ( bh != NULL ) { + if (bh->b_size < byt_per_blk) { + BUG(); + } + bhct += bh->b_size >> (device->sizes.s2b_shift+9); + bh = bh->b_reqnext; + } + + if (private->rdc_data.mode.bits.data_chain) { + rw_cp = dasd_alloc_request (dasd_fba_discipline.name, + 2 + bhct, + sizeof (DE_fba_data_t) + + sizeof (LO_fba_data_t), + device); + } else { + rw_cp = dasd_alloc_request (dasd_fba_discipline.name, + 1 + 2 * bhct, + sizeof (DE_fba_data_t) + + bhct * sizeof (LO_fba_data_t), + device); + } if (!rw_cp) { return NULL; } @@ -294,64 +306,77 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req) LO_data = rw_cp->data + sizeof (DE_fba_data_t); ccw = rw_cp->cpaddr; - define_extent (ccw, DE_data, req->cmd, byt_per_blk, - req->sector, req->nr_sectors); + if (define_extent (ccw, DE_data, req->cmd, byt_per_blk, + req->sector, req->nr_sectors, rw_cp, device)) { + goto clear_rw_cp; + } ccw->flags |= CCW_FLAG_CC; - - for (i = 0, bh = req->bh; bh;) { - if (bh->b_size > byt_per_blk) { - for (size = 0; size < bh->b_size; size += byt_per_blk) { - ccw++; - locate_record (ccw, LO_data, req->cmd, i, 1); - ccw->flags |= CCW_FLAG_CC; - ccw++; - ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI; - ccw->cmd_code = rw_cmd; - ccw->count = byt_per_blk; - set_normalized_cda (ccw, __pa (bh->b_data + size)); - i++; - LO_data++; - } - bh = bh->b_reqnext; - } else { /* group N bhs to fit into byt_per_blk */ - for (size = 0; bh != NULL && size < byt_per_blk;) { - ccw++; - locate_record (ccw, LO_data, req->cmd, i, 1); + ccw ++; + locate_record (ccw, LO_data, req->cmd, 0, + private->rdc_data.mode.bits.data_chain ? bhct : 1, rw_cp, device); + if (ccw->cda == 0) { + goto clear_rw_cp; + } + ccw->flags |= CCW_FLAG_CC; + + bh = req -> bh; + i = 0; + while ( bh != NULL ) { + for (size = 0; size < bh->b_size; size += byt_per_blk) { + ccw ++; + ccw->cmd_code = rw_cmd; + ccw->count = byt_per_blk; + if (dasd_set_normalized_cda (ccw,__pa (bh->b_data + size), rw_cp, device)) { + goto clear_rw_cp; + } + if (private->rdc_data.mode.bits.data_chain) { + ccw->flags |= CCW_FLAG_DC; + } else { ccw->flags |= CCW_FLAG_CC; - ccw++; - if (private->rdc_data.mode.bits.data_chain) { - ccw->flags |= CCW_FLAG_DC|CCW_FLAG_SLI; - } else { - PRINT_WARN ("Cannot chain chunks smaller than one block\n"); - ccw_free_request (rw_cp); - return NULL; - } - ccw->cmd_code = rw_cmd; - ccw->count = bh->b_size; - set_normalized_cda (ccw, __pa (bh->b_data)); - size += bh->b_size; - bh = bh->b_reqnext; - i++; - LO_data++; - } - ccw->flags &= ~CCW_FLAG_DC; - ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI; - if (size != byt_per_blk) { - PRINT_WARN ("Cannot fulfill request smaller than block\n"); - ccw_free_request (rw_cp); - return NULL; - } - } - } + } + } + bh = bh->b_reqnext; + if ( bh != NULL && + !(private->rdc_data.mode.bits.data_chain)) { + ccw++; + i++; + LO_data++; + locate_record (ccw, LO_data, req->cmd, i, 1, rw_cp, device); + if (ccw->cda == 0) { + goto clear_rw_cp; + } + ccw->flags |= CCW_FLAG_CC; + } + } ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC); rw_cp->device = device; rw_cp->expires = 5 * TOD_MIN; /* 5 minutes */ rw_cp->req = req; check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED); + goto out; + clear_rw_cp: + dasd_free_request (rw_cp, device); + rw_cp = NULL; + out: return rw_cp; } +static int +dasd_fba_fill_info (dasd_device_t * device, dasd_information_t * info) +{ + int rc = 0; + info->label_block = 1; + info->FBA_layout = 1; + info->characteristics_size = sizeof (dasd_fba_characteristics_t); + memcpy (info->characteristics, + &((dasd_fba_private_t *) device->private)->rdc_data, + sizeof (dasd_fba_characteristics_t)); + info->confdata_size = 0; + return rc; +} + + static char * dasd_fba_dump_sense (struct dasd_device_t *device, ccw_req_t * req) { @@ -367,25 +392,26 @@ dasd_fba_dump_sense (struct dasd_device_t *device, ccw_req_t * req) return page; } -dasd_discipline_t dasd_fba_discipline = -{ +dasd_discipline_t dasd_fba_discipline = { + owner: THIS_MODULE, name:"FBA ", ebcname:"FBA ", - max_blocks:((PAGE_SIZE >> 1)/sizeof(ccw1_t)-1), + max_blocks:((PAGE_SIZE >> 1) / sizeof (ccw1_t) - 1), id_check:dasd_fba_id_check, check_characteristics:dasd_fba_check_characteristics, do_analysis:dasd_fba_do_analysis, fill_geometry:dasd_fba_fill_geometry, start_IO:dasd_start_IO, + term_IO:dasd_term_IO, examine_error:dasd_fba_examine_error, erp_action:dasd_fba_erp_action, erp_postaction:dasd_fba_erp_postaction, build_cp_from_req:dasd_fba_build_cp_from_req, dump_sense:dasd_fba_dump_sense, - int_handler:dasd_int_handler + int_handler:dasd_int_handler, + fill_info:dasd_fba_fill_info, }; - int dasd_fba_init (void) { @@ -393,18 +419,22 @@ dasd_fba_init (void) printk (KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_fba_discipline.name); ASCEBC (dasd_fba_discipline.ebcname, 4); - dasd_discipline_enq (&dasd_fba_discipline); -#ifdef CONFIG_DASD_DYNAMIC - { - int i; - for (i = 0; i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); i++) { - printk (KERN_INFO PRINTK_HEADER - "We are interested in: CU %04X/%02x\n", - dasd_fba_known_devices[i].ci.hc.ctype, - dasd_fba_known_devices[i].ci.hc.cmode); - s390_device_register (&dasd_fba_known_devices[i]); - } - } + dasd_discipline_add (&dasd_fba_discipline); +#ifdef CONFIG_DASD_DYNAMIC + { + int i; + for (i = 0; + i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); + i++) { + printk (KERN_INFO PRINTK_HEADER + "We are interested in: Dev %04X/%02X @ CU %04X/%02x\n", + dasd_fba_known_devices[i].ci.hc.dtype, + dasd_fba_known_devices[i].ci.hc.dmode, + dasd_fba_known_devices[i].ci.hc.ctype, + dasd_fba_known_devices[i].ci.hc.cmode); + s390_device_register (&dasd_fba_known_devices[i]); + } + } #endif /* CONFIG_DASD_DYNAMIC */ return rc; } @@ -417,16 +447,31 @@ dasd_fba_cleanup( void ) { { int i; for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) { - printk (KERN_INFO PRINTK_HEADER - "We were interested in: CU %04X/%02x\n", - dasd_fba_known_devices[i].ci.hc.ctype, - dasd_fba_known_devices[i].ci.hc.cmode); s390_device_unregister(&dasd_fba_known_devices[i]); } } #endif /* CONFIG_DASD_DYNAMIC */ - dasd_discipline_deq(&dasd_fba_discipline); + dasd_discipline_del(&dasd_fba_discipline); +} + +#ifdef MODULE +int +init_module (void) +{ + int rc = 0; + rc = dasd_fba_init (); + return rc; } + +void +cleanup_module (void) +{ + dasd_fba_cleanup (); + return; +} +#endif + + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/drivers/s390/block/dasd_fba.h b/drivers/s390/block/dasd_fba.h index f78403d85d64..8ddad39f4a20 100644 --- a/drivers/s390/block/dasd_fba.h +++ b/drivers/s390/block/dasd_fba.h @@ -3,7 +3,7 @@ #define DASD_FBA_H typedef -struct DE_fba_data_t { + struct DE_fba_data_t { struct { unsigned char perm:2; /* Permissions on this extent */ unsigned char zero:2; /* Must be zero */ @@ -16,12 +16,12 @@ struct DE_fba_data_t { __u32 ext_loc; /* Extent locator */ __u32 ext_beg; /* logical number of block 0 in extent */ __u32 ext_end; /* logocal number of last block in extent */ -} __attribute__ ((packed)) +} __attribute__ ((packed)) -DE_fba_data_t; + DE_fba_data_t; typedef -struct LO_fba_data_t { + struct LO_fba_data_t { struct { unsigned char zero:4; unsigned char cmd:4; @@ -29,12 +29,12 @@ struct LO_fba_data_t { __u8 auxiliary; __u16 blk_ct; __u32 blk_nr; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -LO_fba_data_t; + LO_fba_data_t; typedef -struct dasd_fba_characteristics_t { + struct dasd_fba_characteristics_t { union { __u8 c; struct { @@ -67,10 +67,10 @@ struct dasd_fba_characteristics_t { __u16 blk_ce; __u32 reserved2; __u16 reserved3; -} __attribute__ ((packed)) +} __attribute__ ((packed)) -dasd_fba_characteristics_t; + dasd_fba_characteristics_t; int dasd_fba_init (void); -void dasd_fba_cleanup(void); +void dasd_fba_cleanup (void); #endif /* DASD_FBA_H */ diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h new file mode 100644 index 000000000000..df0d3f83e26a --- /dev/null +++ b/drivers/s390/block/dasd_int.h @@ -0,0 +1,390 @@ +/* + * File...........: linux/drivers/s390/block/dasd.c + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * + * History of changes (starts July 2000) + * 02/01/01 added dynamic registration of ioctls + */ + +#ifndef DASD_INT_H +#define DASD_INT_H + +#define DASD_API_VERSION 0 + +#include <asm/dasd.h> + +#define CONFIG_DASD_DYNAMIC + +typedef int(*dasd_ioctl_fn_t) (void *inp, int no, long args); +int dasd_ioctl_no_register(struct module *, int no, dasd_ioctl_fn_t handler); +int dasd_ioctl_no_unregister(struct module *, int no, dasd_ioctl_fn_t handler); + +#define DASD_NAME "dasd" +#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) + + +#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 +#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 + +#define DASD_STATE_DEL -1 +#define DASD_STATE_NEW 0 +#define DASD_STATE_KNOWN 1 +#define DASD_STATE_ACCEPT 2 +#define DASD_STATE_INIT 3 +#define DASD_STATE_READY 4 +#define DASD_STATE_ONLINE 5 + + +#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 +#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 +#define DASD_FORMAT_INTENS_INVALIDATE 0x04 +#define DASD_FORMAT_INTENS_CDL 0x08 +#ifdef __KERNEL__ +#include <linux/module.h> +#include <linux/version.h> +#include <linux/major.h> +#include <linux/wait.h> +#include <linux/blk.h> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#include <linux/blkdev.h> +#include <linux/devfs_fs_kernel.h> +#endif +#include <linux/genhd.h> +#include <linux/hdreg.h> +#include <linux/compatmac.h> + +#include <asm/ccwcache.h> +#include <asm/irq.h> +#include <asm/s390dyn.h> +#include <asm/todclk.h> +#include <asm/debug.h> + +/* Kernel Version Compatibility section */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) +typedef struct request *request_queue_t; +#define block_device_operations file_operations +#define __setup(x,y) struct dasd_device_t +#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops) +#define register_disk(dd,dev,partn,ops,size) \ +do { \ + dd->sizes[MINOR(dev)] = size >> 1; \ + resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \ +} while(0) +#define init_waitqueue_head(x) do { *x = NULL; } while(0) +#define blk_cleanup_queue(x) do {} while(0) +#define blk_init_queue(x...) do {} while(0) +#define blk_queue_headactive(x...) do {} while(0) +#define blk_queue_make_request(x) do {} while(0) +#define list_empty(x) (0) +#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ +do { \ + blk_dev[d_major].request_fn = d_request_fn; \ + blk_dev[d_major].queue = d_queue_fn; \ + blk_dev[d_major].current_request = d_current; \ +} while(0) +#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ + major:D_MAJOR, \ + major_name:D_NAME, \ + minor_shift:D_PARTN_BITS, \ + max_p:1 << D_PARTN_BITS, \ + max_nr:D_PER_MAJOR, \ + nr_real:D_PER_MAJOR, +static inline struct request * +dasd_next_request( request_queue_t *queue ) +{ + return *queue; +} +static inline void +dasd_dequeue_request( request_queue_t * q, struct request *req ) +{ + *q = req->next; + req->next = NULL; +} +#else +#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ +do { \ + blk_dev[d_major].queue = d_queue_fn; \ +} while(0) +#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ + major:D_MAJOR, \ + major_name:D_NAME, \ + minor_shift:D_PARTN_BITS, \ + max_p:1 << D_PARTN_BITS, \ + nr_real:D_PER_MAJOR, \ + fops:&dasd_device_operations, +static inline struct request * +dasd_next_request( request_queue_t *queue ) +{ + return blkdev_entry_next_request(&queue->queue_head); +} +static inline void +dasd_dequeue_request( request_queue_t * q, struct request *req ) +{ + blkdev_dequeue_request (req); +} +#endif + +/* dasd_range_t are used for dynamic device att-/detachment */ +typedef struct dasd_devreg_t { + devreg_t devreg; /* the devreg itself */ + /* build a linked list of devregs, needed for cleanup */ + struct list_head list; +} dasd_devreg_t; + +typedef struct { + struct list_head list; + struct module *owner; + int no; + dasd_ioctl_fn_t handler; +} dasd_ioctl_list_t; + +typedef enum { + dasd_era_fatal = -1, /* no chance to recover */ + dasd_era_none = 0, /* don't recover, everything alright */ + dasd_era_msg = 1, /* don't recover, just report... */ + dasd_era_recover = 2 /* recovery action recommended */ +} dasd_era_t; + +/* BIT DEFINITIONS FOR SENSE DATA */ +#define DASD_SENSE_BIT_0 0x80 +#define DASD_SENSE_BIT_1 0x40 +#define DASD_SENSE_BIT_2 0x20 +#define DASD_SENSE_BIT_3 0x10 + +#define check_then_set(where,from,to) \ +do { \ + if ((*(where)) != (from) ) { \ + printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \ + BUG(); \ + } \ + (*(where)) = (to); \ +} while (0) + +#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ +do { \ + int d_devno = d_device->devinfo.devno; \ + int d_irq = d_device->devinfo.irq; \ + char *d_name = d_device->name; \ + int d_major = MAJOR(d_device->kdev); \ + int d_minor = MINOR(d_device->kdev); \ + printk(d_loglevel PRINTK_HEADER \ + "/dev/%s(%d:%d),%04x@0x%x:" \ + d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ +} while(0) + +/* + * struct dasd_sizes_t + * represents all data needed to access dasd with properly set up sectors + */ +typedef +struct dasd_sizes_t { + unsigned long blocks; /* size of volume in blocks */ + unsigned int bp_block; /* bytes per block */ + unsigned int s2b_shift; /* log2 (bp_block/512) */ + unsigned int pt_block; /* from which block to read the partn table */ +} dasd_sizes_t; + +/* + * struct dasd_chanq_t + * represents a queue of channel programs related to a single device + */ +typedef +struct dasd_chanq_t { + ccw_req_t *head; + ccw_req_t *tail; +} dasd_chanq_t; + +#define DASD_DEVICE_FORMAT_STRING "Device: %p" +#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_event(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); +#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ +do {\ + if ( d_device->debug_area != NULL )\ + debug_sprintf_exception(d_device->debug_area,d_level,\ + DASD_DEVICE_FORMAT_STRING d_str "\n",\ + d_device, d_data);\ +} while(0); + +#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" +#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_event(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); +#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ +do {\ + if ( dasd_debug_area != NULL )\ + debug_sprintf_exception(dasd_debug_area, d_level,\ + DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ + d_fn, d_data);\ +} while(0); + +struct dasd_device_t; +struct request; + +/* + * signatures for the functions of dasd_discipline_t + * make typecasts much easier + */ +typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); +typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); + +typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *); +typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); +typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *); +typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *); +typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *); +typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *); +typedef int (*dasd_io_starter_fn_t) (ccw_req_t *); +typedef int (*dasd_io_stopper_fn_t) (ccw_req_t *); +typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *); +typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat); +typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *); +typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *); +typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *); +typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *); +typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *); +typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *); +typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *); +typedef int (*dasd_info_fn_t) (struct dasd_device_t *, dasd_information_t *); +typedef int (*dasd_use_count_fn_t) (int); + + +/* + * the dasd_discipline_t is + * sth like a table of virtual functions, if you think of dasd_eckd + * inheriting dasd... + * no, currently we are not planning to reimplement the driver in C++ + */ +typedef struct dasd_discipline_t { + struct module *owner; + char ebcname[8]; /* a name used for tagging and printks */ + char name[8]; /* a name used for tagging and printks */ + int max_blocks; /* maximum number of blocks to be chained */ + dasd_ck_id_fn_t id_check; /* to check sense data */ + dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ + dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ + dasd_do_analysis_fn_t do_analysis; /* to complete the analysis of the volume */ + dasd_fill_geometry_fn_t fill_geometry; /* to set up hd_geometry */ + dasd_io_starter_fn_t start_IO; + dasd_io_stopper_fn_t term_IO; + dasd_format_fn_t format_device; /* to format the device */ + dasd_error_examine_fn_t examine_error; + dasd_error_analyse_fn_t erp_action; + dasd_erp_analyse_fn_t erp_postaction; + dasd_cp_builder_fn_t build_cp_from_req; + dasd_dump_sense_fn_t dump_sense; + dasd_int_handler_fn_t int_handler; + dasd_reserve_fn_t reserve; + dasd_release_fn_t release; + dasd_merge_cp_fn_t merge_cp; + dasd_info_fn_t fill_info; + struct list_head list; /* used for list of disciplines */ +} dasd_discipline_t; + +#define DASD_DEFAULT_FEATURES 0 +#define DASD_FEATURE_READONLY 1 + +/* dasd_range_t are used for ordering the DASD devices */ +typedef struct dasd_range_t { + unsigned int from; /* first DASD in range */ + unsigned int to; /* last DASD in range */ + char discipline[4]; /* placeholder to force discipline */ + int features; + struct list_head list; /* next one in linked list */ +} dasd_range_t; + + + +#define DASD_MAJOR_INFO_REGISTERED 1 +#define DASD_MAJOR_INFO_IS_STATIC 2 + +typedef struct major_info_t { + struct list_head list; + struct dasd_device_t **dasd_device; + int flags; + struct gendisk gendisk; /* actually contains the major number */ +} __attribute__ ((packed)) major_info_t; + +typedef struct dasd_device_t { + s390_dev_info_t devinfo; + dasd_discipline_t *discipline; + int level; + atomic_t open_count; + kdev_t kdev; + major_info_t *major_info; + struct dasd_chanq_t queue; + wait_queue_head_t wait_q; + request_queue_t *request_queue; + struct timer_list timer; + devstat_t dev_status; /* needed ONLY!! for request_irq */ + dasd_sizes_t sizes; + char name[16]; /* The name of the device in /dev */ + char *private; /* to be used by the discipline internally */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + devfs_handle_t devfs_entry; +#endif /* LINUX_IS_24 */ + struct tq_struct bh_tq; + atomic_t bh_scheduled; + debug_info_t *debug_area; + dasd_profile_info_t profile; + ccw_req_t *init_cqr; + atomic_t plugged; + void* lowmem_cqr; + void* lowmem_ccws; + void* lowmem_idals; + void* lowmem_idal_ptr; +} dasd_device_t; + +int dasd_init (void); +void dasd_discipline_add(dasd_discipline_t *); +void dasd_discipline_del(dasd_discipline_t *); +int dasd_start_IO (ccw_req_t *); +int dasd_term_IO (ccw_req_t *); +void dasd_int_handler (int , void *, struct pt_regs *); +ccw_req_t *dasd_default_erp_action (ccw_req_t *); +ccw_req_t *dasd_default_erp_postaction (ccw_req_t *); +inline void dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); +inline void dasd_chanq_enq (dasd_chanq_t *, ccw_req_t *); +inline void dasd_chanq_enq_head (dasd_chanq_t *, ccw_req_t *); +ccw_req_t *dasd_alloc_request (char *, int, int, dasd_device_t *); +void dasd_free_request (ccw_req_t *, dasd_device_t *); +int dasd_oper_handler (int irq, devreg_t * devreg); +void dasd_schedule_bh (dasd_device_t *); +int dasd_sleep_on_req(ccw_req_t*); +int dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device ); + +extern debug_info_t *dasd_debug_area; +extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); + +#endif /* __KERNEL__ */ + +#endif /* DASD_H */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 4109e29abaf1..371141778698 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -624,7 +624,7 @@ static void msgi_end(struct Scsi_Host *shpnt); static void parerr_run(struct Scsi_Host *shpnt); static void rsti_run(struct Scsi_Host *shpnt); -static void complete(struct Scsi_Host *shpnt); +static void is_complete(struct Scsi_Host *shpnt); /* * driver states @@ -1869,7 +1869,7 @@ static void run(void) struct Scsi_Host *shpnt = aha152x_host[i]; if (shpnt && HOSTDATA(shpnt)->service) { HOSTDATA(shpnt)->service=0; - complete(shpnt); + is_complete(shpnt); } } } @@ -2935,7 +2935,7 @@ static void rsti_run(struct Scsi_Host *shpnt) * bottom-half handler * */ -static void complete(struct Scsi_Host *shpnt) +static void is_complete(struct Scsi_Host *shpnt) { int dataphase; unsigned long flags; diff --git a/drivers/scsi/aic7xxx/aic7xxx.c b/drivers/scsi/aic7xxx/aic7xxx.c index be44ba5b2746..ed3ffbccac15 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.c +++ b/drivers/scsi/aic7xxx/aic7xxx.c @@ -1343,22 +1343,21 @@ ahc_print_scb(struct scb *scb) hscb->scsiid, hscb->lun, hscb->cdb_len); - i = 0; printf("Shared Data: %#02x %#02x %#02x %#02x\n", - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++]); + hscb->shared_data.cdb[0], + hscb->shared_data.cdb[1], + hscb->shared_data.cdb[2], + hscb->shared_data.cdb[3]); printf(" %#02x %#02x %#02x %#02x\n", - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++]); + hscb->shared_data.cdb[4], + hscb->shared_data.cdb[5], + hscb->shared_data.cdb[6], + hscb->shared_data.cdb[7]); printf(" %#02x %#02x %#02x %#02x\n", - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++], - hscb->shared_data.cdb[i++]); + hscb->shared_data.cdb[8], + hscb->shared_data.cdb[9], + hscb->shared_data.cdb[10], + hscb->shared_data.cdb[11]); printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", ahc_le32toh(hscb->dataptr), ahc_le32toh(hscb->datacnt), diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 8776f56d3c32..86b98dbc9fca 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -11,7 +11,7 @@ * enable 32 bit fifo transfer * support cdrom & remove device run ultra speed * fix disconnect bug 2000/12/21 - * support atp880 chip lvd u160 2001/05/15 + * support atp880 chip lvd u160 2001/05/15 (7.1) */ #include <linux/module.h> @@ -65,8 +65,10 @@ struct atp_unit unsigned short wide_idu; unsigned short active_idu; unsigned short ultra_map; + unsigned short async; unsigned short deviceid; unsigned char ata_cdbu[16]; + unsigned char sp[16]; Scsi_Cmnd *querequ[qcnt]; struct atp_id { @@ -1694,8 +1696,9 @@ void is880(unsigned long host, unsigned int wkport) static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6}; static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; - static unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; - static unsigned char synw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; + unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; + static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; + unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 }; struct atp_unit *dev = &atp_unit[host]; @@ -1834,17 +1837,18 @@ inq_ok: if ((mbuf[7] & 0x60) == 0) { goto not_wide; } - if ((dev->global_map & 0x20) == 0) { + if ((i < 8) && ((dev->global_map & 0x20) == 0)) { goto not_wide; } if (lvdmode == 0) { goto chg_wide; } - if ((mbuf[2] & 0x07) < 0x03) // force u2 + if (dev->sp[i] != 0x04) // force u2 { goto chg_wide; } + tmport = wkport + 0x5b; outb(0x01, tmport); tmport = wkport + 0x43; @@ -2129,10 +2133,28 @@ not_wide: if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) { - goto set_sync; + m = 1; + m = m << i; + if ((dev->async & m) != 0) + { + goto set_sync; + } } continue; set_sync: + if (dev->sp[i] == 0x02) + { + synu[4]=0x0c; + synuw[4]=0x0c; + } + else + { + if (dev->sp[i] >= 0x03) + { + synu[4]=0x0a; + synuw[4]=0x0a; + } + } tmport = wkport + 0x5b; j = 0; if ((m & dev->wide_idu) != 0) { @@ -2175,7 +2197,11 @@ try_sync: if ((inb(tmport) & 0x01) != 0) { tmport -= 0x06; if ((m & dev->wide_idu) != 0) { - outb(synw[j++], tmport); + if ((m & dev->ultra_map) != 0) { + outb(synuw[j++], tmport); + } else { + outb(synw[j++], tmport); + } } else { if ((m & dev->ultra_map) != 0) { outb(synu[j++], tmport); @@ -2321,13 +2347,13 @@ tar_dcons: /* return non-zero on detection */ int atp870u_detect(Scsi_Host_Template * tpnt) { - unsigned char irq, h, k; + unsigned char irq, h, k, m; unsigned long flags; unsigned int base_io, error, tmport; unsigned short index = 0; struct pci_dev *pdev[3]; unsigned char chip_ver[3], host_id; - unsigned short dev_id[3]; + unsigned short dev_id[3], n; struct Scsi_Host *shpnt = NULL; int tmpcnt = 0; int count = 0; @@ -2368,6 +2394,7 @@ int atp870u_detect(Scsi_Host_Template * tpnt) } for (k = 0; k < 16; k++) { dev->id[k].curr_req = 0; + dev->sp[k] = 0x04; } } h = 0; @@ -2500,7 +2527,7 @@ int atp870u_detect(Scsi_Host_Template * tpnt) host_id = inb(base_io + 0x39); host_id >>= 0x04; - printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d IO:%x, IRQ:%d.\n" + printk(KERN_INFO " ACARD AEC-67160 PCI Ultra160 LVD/SE SCSI Adapter: %d IO:%x, IRQ:%d.\n" ,h, base_io, irq); dev->ioport = base_io + 0x40; dev->pciport = base_io + 0x28; @@ -2515,11 +2542,67 @@ int atp870u_detect(Scsi_Host_Template * tpnt) dev->global_map = inb(tmport); tmport += 0x07; dev->ultra_map = inw(tmport); - if (dev->ultra_map == 0) { - dev->scam_on = 0x00; - dev->global_map = 0x20; - dev->ultra_map = 0xffff; + + n=0x3f09; +next_fblk: + if (n >= 0x4000) + { + goto flash_ok; } + m=0; + outw(n,base_io + 0x34); + n += 0x0002; + if (inb(base_io + 0x30) == 0xff) + { + goto flash_ok; + } + dev->sp[m++]=inb(base_io + 0x30); + dev->sp[m++]=inb(base_io + 0x31); + dev->sp[m++]=inb(base_io + 0x32); + dev->sp[m++]=inb(base_io + 0x33); + outw(n,base_io + 0x34); + n += 0x0002; + dev->sp[m++]=inb(base_io + 0x30); + dev->sp[m++]=inb(base_io + 0x31); + dev->sp[m++]=inb(base_io + 0x32); + dev->sp[m++]=inb(base_io + 0x33); + outw(n,base_io + 0x34); + n += 0x0002; + dev->sp[m++]=inb(base_io + 0x30); + dev->sp[m++]=inb(base_io + 0x31); + dev->sp[m++]=inb(base_io + 0x32); + dev->sp[m++]=inb(base_io + 0x33); + outw(n,base_io + 0x34); + n += 0x0002; + dev->sp[m++]=inb(base_io + 0x30); + dev->sp[m++]=inb(base_io + 0x31); + dev->sp[m++]=inb(base_io + 0x32); + dev->sp[m++]=inb(base_io + 0x33); + n += 0x0018; + goto next_fblk; +flash_ok: + outw(0,base_io + 0x34); + dev->ultra_map=0; + dev->async = 0; + for (k=0; k < 16; k++) + { + n=1; + n = n << k; + if (dev->sp[k] > 1) + { + dev->ultra_map |= n; + } + else + { + if (dev->sp[k] == 0) + { + dev->async |= n; + } + } + } + dev->async = ~(dev->async); + outb(dev->global_map,base_io + 0x35); + shpnt = scsi_register(tpnt, 4); if(shpnt==NULL) return count; @@ -2557,6 +2640,7 @@ int atp870u_detect(Scsi_Host_Template * tpnt) tmport = base_io + 0x51; outb(0x20, tmport); + tscam(h); is880(h, base_io); tmport = base_io + 0x38; outb(0xb0, tmport); @@ -2646,7 +2730,7 @@ find_adp: { printk(" %2x ",workrequ->cmnd[k]); } - printk(" last_lenu= %lx ",dev->id[j].last_lenu); + printk(" last_lenu= %x ",dev->id[j].last_lenu); } } return (SCSI_ABORT_SNOOZE); @@ -2680,7 +2764,7 @@ const char *atp870u_info(struct Scsi_Host *notused) { static char buffer[128]; - strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.4+ac "); + strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.5+ac "); return buffer; } @@ -2725,7 +2809,7 @@ int atp870u_proc_info(char *buffer, char **start, off_t offset, int length, if (offset == 0) { memset(buff, 0, sizeof(buff)); } - size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.4+ac\n"); + size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.5+ac\n"); len += size; pos = begin + len; size = 0; @@ -2791,4 +2875,3 @@ int atp870u_release (struct Scsi_Host *pshost) static Scsi_Host_Template driver_template = ATP870U; #include "scsi_module.c" - diff --git a/drivers/scsi/cpqfc.Readme b/drivers/scsi/cpqfc.Readme index 1d795a447a4d..769a7f5122cc 100644 --- a/drivers/scsi/cpqfc.Readme +++ b/drivers/scsi/cpqfc.Readme @@ -6,6 +6,23 @@ Tested in single and dual HBA configuration, 32 and 64bit busses, 33 and 66MHz. Only supports FC-AL. SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() max of 128k bytes contiguous. + +Ver 2.0.2 July 23, 2001 + Changed the semiphore changes so the driver would compile in 2.4.7. + This version is for 2.4.7 and beyond. + +Ver 2.0.1 May 7, 2001 + Merged version 1.3.6 fixes into version 2.0.0. + +Ver 2.0.0 May 7, 2001 + Fixed problem so spinlock is being initialized to UNLOCKED. + Fixed updated driver so it compiles in the 2.4 tree. + + Ver 1.3.6 Feb 27, 2001 + Added Target_Device_Reset function for SCSI error handling + Fixed problem with not reseting addressing mode after implicit logout + + Ver 1.3.4 Sep 7, 2000 Added Modinfo information Fixed problem with statically linking the driver @@ -212,5 +229,5 @@ is used), logical volumes on the RA4x00 will no longer be visible. Send questions/comments to: -donald.zimmerman@compaq.com -dszimmerman@yahoo.com +Amy Vanzant-Hodge (fibrechannel@compaq.com) + diff --git a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h index 966c63b8c3d5..b65eca0ceb4f 100644 --- a/drivers/scsi/cpqfcTS.h +++ b/drivers/scsi/cpqfcTS.h @@ -5,11 +5,13 @@ // These functions are required by the Linux SCSI layers extern int cpqfcTS_detect(Scsi_Host_Template *); extern int cpqfcTS_release(struct Scsi_Host *); -const char * cpqfcTS_info(struct Scsi_Host *); +extern const char * cpqfcTS_info(struct Scsi_Host *); extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int); extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); extern int cpqfcTS_abort(Scsi_Cmnd *); extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int); +extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd); +extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *); extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]); extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg); @@ -24,8 +26,10 @@ extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg); proc_info: cpqfcTS_proc_info, \ ioctl: cpqfcTS_ioctl, \ queuecommand: cpqfcTS_queuecommand, \ - eh_abort_handler: cpqfcTS_abort, \ + eh_device_reset_handler: cpqfcTS_eh_device_reset, \ + eh_abort_handler: cpqfcTS_eh_abort, \ reset: cpqfcTS_reset, \ + abort: cpqfcTS_abort, \ bios_param: cpqfcTS_biosparam, \ can_queue: CPQFCTS_REQ_QUEUE_LEN, \ this_id: -1, \ @@ -33,7 +37,8 @@ extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg); cmd_per_lun: CPQFCTS_CMD_PER_LUN, \ present: 0, \ unchecked_isa_dma: 0, \ - use_clustering: ENABLE_CLUSTERING \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 1 \ } #endif /* CPQFCTS_H */ diff --git a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c index 31f4750a9cff..b0e51829b214 100644 --- a/drivers/scsi/cpqfcTScontrol.c +++ b/drivers/scsi/cpqfcTScontrol.c @@ -42,11 +42,7 @@ #include <linux/unistd.h> #include <asm/io.h> // struct pt_regs for IRQ handler & Port I/O #include <asm/irq.h> -#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18) -#include <asm/spinlock.h> -#else #include <linux/spinlock.h> -#endif #include "sd.h" #include "hosts.h" // Scsi_Host definition for INT handler diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c index 96894bf13ba4..03ecac442817 100644 --- a/drivers/scsi/cpqfcTSinit.c +++ b/drivers/scsi/cpqfcTSinit.c @@ -49,11 +49,7 @@ #include <asm/io.h> #include <asm/uaccess.h> // ioctl related #include <asm/irq.h> -#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18) -#include <asm/spinlock.h> -#else #include <linux/spinlock.h> -#endif #include "sd.h" #include <scsi/scsi_ioctl.h> #include "hosts.h" @@ -62,10 +58,15 @@ #include "cpqfcTS.h" +#include <linux/config.h> #include <linux/module.h> +#include <linux/version.h> + /* Embedded module documentation macros - see module.h */ MODULE_AUTHOR("Compaq Computer Corporation"); MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA"); + +int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags); // This struct was originally defined in // /usr/src/linux/include/linux/proc_fs.h @@ -104,24 +105,24 @@ static void Cpqfc_initHBAdata( CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev ) // since x86 port space is 64k, we only need the lower 16 bits cpqfcHBAdata->fcChip.Registers.IOBaseL = - PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; cpqfcHBAdata->fcChip.Registers.IOBaseU = - PciDev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK; + PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK; // 32-bit memory addresses cpqfcHBAdata->fcChip.Registers.MemBase = - PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK; + PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK; cpqfcHBAdata->fcChip.Registers.ReMapMemBase = - ioremap( PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK, + ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK, 0x200); cpqfcHBAdata->fcChip.Registers.RAMBase = - PciDev->base_address[4]; + PciDev->resource[4].start; cpqfcHBAdata->fcChip.Registers.SROMBase = // NULL for HP TS adapter - PciDev->base_address[5]; + PciDev->resource[5].start; // now the Tachlite chip registers // the REGISTER struct holds both the physical address & last @@ -296,10 +297,14 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate) continue; DEBUG_PCI( printk(" HBA found!\n")); DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) ); - DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[0])); - DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[1])); - DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[2])); - DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[3])); + DEBUG_PCI(printk(" PciDev->baseaddress[0]= %lx\n", + PciDev->resource[0].start)); + DEBUG_PCI(printk(" PciDev->baseaddress[1]= %lx\n", + PciDev->resource[1].start)); + DEBUG_PCI(printk(" PciDev->baseaddress[2]= %lx\n", + PciDev->resource[2].start)); + DEBUG_PCI(printk(" PciDev->baseaddress[3]= %lx\n", + PciDev->resource[3].start)); scsi_set_pci_device(HostAdapter, PciDev); HostAdapter->irq = PciDev->irq; // copy for Scsi layers @@ -308,7 +313,7 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate) // for a total I/O port address space of 512 bytes. // mask out the I/O port address (lower) & record HostAdapter->io_port = (unsigned int) - PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; HostAdapter->n_io_port = 0xff; // i.e., expect 128 targets (arbitrary number), while the @@ -316,7 +321,6 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate) HostAdapter->max_id = 0; // incremented as devices log in HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses? - HostAdapter->hostt->use_new_eh_code = 1; // new error handling // get the pointer to our HBA specific data... (one for // each HBA on the PCI bus(ses)). @@ -333,7 +337,7 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate) Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields cpqfcHBAdata->HBAnum = NumberOfAdapters; - + cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED; // request necessary resources and check for conflicts if( request_irq( HostAdapter->irq, @@ -414,9 +418,12 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate) // slowest(worst) case, measured on 1Gb Finisar GT analyzer int wait_time; + unsigned long flags=0; + + spin_unlock_irqrestore(&io_request_lock, flags); for( wait_time = jiffies + 4*HZ; wait_time > jiffies; ) schedule(); // (our worker task needs to run) - + spin_lock_irqsave(&io_request_lock, flags); } NumberOfAdapters++; @@ -458,7 +465,7 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) Scsi_Cmnd *ScsiPassThruCmnd; unsigned long flags; - ENTER("cpqfcTS_ioctl"); + ENTER("cpqfcTS_ioctl "); // can we find an FC device mapping to this SCSI target? DumCmnd.channel = ScsiDev->channel; // For searching @@ -476,6 +483,7 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) else // we know what FC device to operate on... { + // printk("ioctl CMND %d", Cmnd); switch (Cmnd) { // Passthrough provides a mechanism to bypass the RAID @@ -496,8 +504,8 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) return -EPERM; // copy the caller's struct to our space. - copy_from_user_ret( &ioc, arg, - sizeof( VENDOR_IOCTL_REQ), -EFAULT); + if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ))) + return( -EFAULT); vendor_cmd = ioc.argp; // i.e., CPQ specific command struct @@ -512,13 +520,14 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) // Now build a SCSI_CMND to pass down... // This function allocates and sets Scsi_Cmnd ptrs such as // ->channel, ->target, ->host - ScsiPassThruCmnd = scsi_allocate_device(NULL, ScsiDev, 1); + ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1); // Need data from user? // make sure caller's buffer is in kernel space. if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) && vendor_cmd->len) - copy_from_user_ret( buf, vendor_cmd->bufp, vendor_cmd->len, -EFAULT); + if( copy_from_user( buf, vendor_cmd->bufp, vendor_cmd->len)) + return( -EFAULT); // copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below) memcpy( &ScsiPassThruCmnd->cmnd[0], @@ -590,16 +599,17 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) scsi_release_command(ScsiPassThruCmnd); // "de-allocate" ScsiPassThruCmnd = NULL; - if (!SDpnt->was_reset && SDpnt->scsi_request_fn) - (*SDpnt->scsi_request_fn)(); + // if (!SDpnt->was_reset && SDpnt->scsi_request_fn) + // (*SDpnt->scsi_request_fn)(); - wake_up(&SDpnt->device_wait); + wake_up(&SDpnt->scpnt_wait); spin_unlock_irqrestore(&io_request_lock, flags); // need to pass data back to user (space)? if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) && vendor_cmd->len ) - copy_to_user_ret( vendor_cmd->bufp, buf, vendor_cmd->len, -EFAULT); + if( copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len)) + return( -EFAULT); if( buf) kfree( buf); @@ -621,8 +631,8 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) pciinfo.board_id = cpqfcHBAdata->PciDev->device | (cpqfcHBAdata->PciDev->vendor <<16); - copy_to_user_ret( arg, &pciinfo, - sizeof(cpqfc_pci_info_struct), -EFAULT); + if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct))) + return( -EFAULT); return 0; } @@ -634,8 +644,8 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) if( !arg) return -EINVAL; - copy_to_user_ret( arg, &DriverVer, - sizeof(DriverVer), -EFAULT); + if(copy_to_user( arg, &DriverVer, sizeof(DriverVer))) + return( -EFAULT); return 0; } @@ -657,6 +667,17 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]); break; + + + case SCSI_IOCTL_FC_TDR: + + result = cpqfcTS_TargetDeviceReset( ScsiDev, 0); + + break; + + + + default: result = -EINVAL; break; @@ -1351,13 +1372,20 @@ int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *)) int cpqfcTS_abort(Scsi_Cmnd *Cmnd) { +// printk(" cpqfcTS_abort called?? \n"); + return 0; +} + +int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd) +{ + struct Scsi_Host *HostAdapter = Cmnd->host; // get the pointer to our Scsi layer HBA buffer CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; PTACHYON fcChip = &cpqfcHBAdata->fcChip; FC_EXCHANGES *Exchanges = fcChip->Exchanges; int i; - ENTER("cpqfcTS_abort"); + ENTER("cpqfcTS_eh_abort"); Cmnd->result = DID_ABORT <<16; // assume we'll find it @@ -1443,28 +1471,117 @@ int cpqfcTS_abort(Scsi_Cmnd *Cmnd) Done: // panic("_abort"); - LEAVE("cpqfcTS_abort"); + LEAVE("cpqfcTS_eh_abort"); return 0; // (see scsi.h) } +// FCP-SCSI Target Device Reset +// See dpANS Fibre Channel Protocol for SCSI +// X3.269-199X revision 12, pg 25 - -// To be done... -int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) +int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, + unsigned int reset_flags) { - int return_status = SUCCESS; + int timeout = 10*HZ; + int retries = 1; + char scsi_cdb[12]; + unsigned long flags; + int result; + Scsi_Cmnd * SCpnt; + Scsi_Device * SDpnt; - ENTER("cpqfcTS_reset"); + // printk(" ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags); - + if (ScsiDev->host->eh_active) return FAILED; - LEAVE("cpqfcTS_reset"); - return return_status; -} + memset( scsi_cdb, 0, sizeof( scsi_cdb)); + scsi_cdb[0] = RELEASE; + spin_lock_irqsave(&io_request_lock, flags); + + // allocate with wait = true, interruptible = false + SCpnt = scsi_allocate_device(ScsiDev, 1, 0); + { + DECLARE_COMPLETION(wait); + + SCpnt->SCp.buffers_residual = FCP_TARGET_RESET; + + SCpnt->request.waiting = &wait; + scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries); + spin_unlock_irqrestore(&io_request_lock, flags); + wait_for_completion(&wait); + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->request.waiting = NULL; + } + +/* + if(driver_byte(SCpnt->result) != 0) + switch(SCpnt->sense_buffer[2] & 0xf) { + case ILLEGAL_REQUEST: + if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; + else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); + break; + case NOT_READY: // This happens if there is no disc in drive + if(dev->removable && (cmd[0] != TEST_UNIT_READY)){ + printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); + break; + } + case UNIT_ATTENTION: + if (dev->removable){ + dev->changed = 1; + SCpnt->result = 0; // This is no longer considered an error + // gag this error, VFS will log it anyway /axboe + // printk(KERN_INFO "Disc change detected.\n"); + break; + }; + default: // Fall through for non-removable media + printk("SCSI error: host %d id %d lun %d return code = %x\n", + dev->host->host_no, + dev->id, + dev->lun, + SCpnt->result); + printk("\tSense class %x, sense error %x, extended sense %x\n", + sense_class(SCpnt->sense_buffer[0]), + sense_error(SCpnt->sense_buffer[0]), + SCpnt->sense_buffer[2] & 0xf); + + }; +*/ + result = SCpnt->result; + + SDpnt = SCpnt->device; + scsi_release_command(SCpnt); + SCpnt = NULL; + + // if (!SDpnt->was_reset && SDpnt->scsi_request_fn) + // (*SDpnt->scsi_request_fn)(); + + wake_up(&SDpnt->scpnt_wait); + spin_unlock_irqrestore(&io_request_lock, flags); + // printk(" LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n"); + return SUCCESS; +} + + +int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd) +{ + Scsi_Device *SDpnt = Cmnd->device; + // printk(" ENTERING cpqfcTS_eh_device_reset() \n"); + return cpqfcTS_TargetDeviceReset( SDpnt, 0); +} + + +int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) +{ + + ENTER("cpqfcTS_reset"); + + LEAVE("cpqfcTS_reset"); + return SCSI_RESET_ERROR; /* Bus Reset Not supported */ +} /* This function determines the bios parameters for a given harddisk. These tend to be numbers that are made up by the @@ -1805,15 +1922,7 @@ void* fcMemManager( ALIGNED_MEM *dynamic_mem, ULONG n_alloc, ULONG ab, } - - -#ifdef MODULE - static Scsi_Host_Template driver_template = CPQFCTS; #include "scsi_module.c" - -#endif - - diff --git a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h index 2680228a411e..c573d32b9f60 100644 --- a/drivers/scsi/cpqfcTSstructs.h +++ b/drivers/scsi/cpqfcTSstructs.h @@ -29,9 +29,9 @@ for( wait_time=jiffies + (secs*HZ); \ wait_time > jiffies ;) ; } #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define VER_MAJOR 1 -#define VER_MINOR 3 -#define VER_SUBMINOR 4 +#define VER_MAJOR 2 +#define VER_MINOR 0 +#define VER_SUBMINOR 2 // Macros for kernel (esp. SMP) tracing using a PCI analyzer // (e.g. x86). @@ -225,6 +225,7 @@ typedef __u8 BOOLEAN; #define ELS_RJT 0x1000000 #define SCSI_REPORT_LUNS 0x0A0 #define REPORT_LUNS 0xA0 // SCSI-3 command op-code +#define FCP_TARGET_RESET 0x200 #define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame diff --git a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c index 5e54d0455887..d7bd4d9963bb 100644 --- a/drivers/scsi/cpqfcTSworker.c +++ b/drivers/scsi/cpqfcTSworker.c @@ -149,7 +149,6 @@ static void IssueReportLunsCommand( CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs); - // (see scsi_error.c comments on kernel task creation) void cpqfcTSWorkerThread( void *host) @@ -1069,6 +1068,7 @@ void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata, pFcPort->flogi = FALSE; pFcPort->LOGO_timer = 0; pFcPort->device_blocked = TRUE; // block Scsi Requests + pFcPort->ScsiNexus.VolumeSetAddressing=0; } @@ -2934,7 +2934,6 @@ static void IssueReportLunsCommand( ULONG ulStatus; UCHAR *ucBuff; - if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn { printk("Discard Q'd ReportLun command\n"); @@ -2976,7 +2975,7 @@ static void IssueReportLunsCommand( Cmnd->channel = pLoggedInPort->ScsiNexus.channel; Cmnd->target = pLoggedInPort->ScsiNexus.target; - + ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, @@ -3404,7 +3403,7 @@ PFC_LOGGEDIN_PORT fcFindLoggedInPort( if( port_id_valid ) // look for alpa first { if( pLoggedInPort->port_id == port_id ) - break; // found it! + break; // found it! } if( wwn_valid ) // look for wwn second { @@ -4326,7 +4325,6 @@ ULONG cpqfcTSBuildExchange( break; - case BLS_ABTS: // FC defined basic link service command ABTS // Abort Sequence @@ -4498,6 +4496,7 @@ ULONG cpqfcTSBuildExchange( // Fibre Channel SCSI 'originator' sequences... // (originator means 'initiator' in FCP-SCSI) + case SCSI_IWE: // TachLite Initiator Write Entry { PFC_LOGGEDIN_PORT pLoggedInPort = @@ -6171,7 +6170,18 @@ static int build_FCP_payload( Scsi_Cmnd *Cmnd, // 4 bytes Control Field FCP_CNTL *payload++ = 0; // byte 0: (MSB) reserved *payload++ = 0; // byte 1: task codes - *payload++ = 0; // byte 2: task management flags + + // byte 2: task management flags + // another "use" of the spare field to accomplish TDR + // note combination needed + if( (Cmnd->cmnd[0] == RELEASE) && + (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) ) + { + Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR + *payload++ = 0x20; // target device reset bit + } + else + *payload++ = 0; // no TDR // byte 3: (LSB) execution management codes // bit 0 write, bit 1 read (don't set together) diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index cb96ac3ba5e1..0815d1954be3 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -9,7 +9,7 @@ Ver.0.1 Initial version This software may be used and distributed according to the terms of - the GNU General Public License. + the GNU Public License. ======================================================================*/ @@ -23,7 +23,7 @@ ***********************************************************************/ -/* $Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $ */ +/* $Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $ */ #ifdef NSP_KERNEL_2_2 #include <pcmcia/config.h> @@ -41,6 +41,7 @@ #include <linux/delay.h> #include <linux/tqueue.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/major.h> #include <linux/blk.h> #include <linux/stat.h> @@ -71,7 +72,7 @@ MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); MODULE_PARM_DESC(pc_debug, "set debug level"); -static char *version = "$Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $"; +static char *version = "$Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $"; #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) #else #define DEBUG(n, args...) /* */ @@ -90,13 +91,14 @@ typedef struct scsi_info_t { struct bus_operations *bus; } scsi_info_t; -static void nsp_release(u_long arg); -static int nsp_event(event_t event, int priority, +static void nsp_cs_release(u_long arg); +static int nsp_cs_event(event_t event, int priority, event_callback_args_t *args); -static dev_link_t *nsp_attach(void); -static void nsp_detach(dev_link_t *); +static dev_link_t *nsp_cs_attach(void); +static void nsp_cs_detach(dev_link_t *); static int nsp_detect(Scsi_Host_Template * ); -static const char * nsp_info(struct Scsi_Host *); +static int nsp_release(struct Scsi_Host *shpnt); +static const char * nsp_info(struct Scsi_Host *shpnt); static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); static int nsp_abort(Scsi_Cmnd *); static int nsp_reset(Scsi_Cmnd *, unsigned int); @@ -130,25 +132,29 @@ static char nspinfo[100]; /* description */ /* /usr/src/linux/drivers/scsi/hosts.h */ static Scsi_Host_Template driver_template = { /* next: NULL,*/ -/* proc_dir: NULL,*/ +#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE) + proc_dir: &proc_scsi_nsp, /* kernel 2.2 */ +#else + proc_name: "nsp_cs", /* kernel 2.4 */ +#endif /* proc_info: NULL,*/ name: "WorkBit NinjaSCSI-3/32Bi", detect: nsp_detect, -/* release: NULL,*/ + release: nsp_release, info: nsp_info, /* command: NULL,*/ queuecommand: nsp_queuecommand, /* eh_strategy_handler: nsp_eh_strategy,*/ -/* eh_abort_handler: nsp_eh_abort,*/ -/* eh_device_reset_handler: nsp_eh_device_reset,*/ + eh_abort_handler: nsp_eh_abort, + eh_device_reset_handler: nsp_eh_device_reset, eh_bus_reset_handler: nsp_eh_bus_reset, -/* eh_host_reset_handler: nsp_eh_host_reset,*/ + eh_host_reset_handler: nsp_eh_host_reset, abort: nsp_abort, reset: nsp_reset, /* slave_attach: NULL,*/ -/* bios_param: nsp_biosparam,*/ +/* bios_param: NULL,*/ can_queue: 1, - this_id: -1, + this_id: SCSI_INITIATOR_ID, sg_tablesize: SG_ALL, cmd_per_lun: 1, /* present: 0,*/ @@ -172,25 +178,24 @@ static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) //unsigned int base = SCpnt->host->io_port; unsigned char target = SCpnt->target; #endif + nsp_hw_data *data = &nsp_data; DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n", SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); - //DEBUG(0, " before CurrentSC=0x%p\n", nsp_data.CurrentSC); + //DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC); - if(nsp_data.CurrentSC != NULL) { + if(data->CurrentSC != NULL) { printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n"); - nsp_data.CurrentSC = NULL; - SCpnt->result = DID_BAD_TARGET << 16; + data->CurrentSC = NULL; + SCpnt->result = DID_BAD_TARGET << 16; done(SCpnt); - return FAILED; + return FALSE; } -#ifdef PCMCIA_DEBUG show_command(SCpnt); -#endif SCpnt->scsi_done = done; - nsp_data.CurrentSC = SCpnt; + data->CurrentSC = SCpnt; RESID = SCpnt->request_bufflen; SCpnt->SCp.Status = -1; @@ -217,62 +222,63 @@ static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) SCpnt->SCp.buffers_residual = 0; } - if(nsphw_start_selection(SCpnt) == FALSE) { + if(nsphw_start_selection(SCpnt, data) == FALSE) { DEBUG(0, " selection fail\n"); - nsp_data.CurrentSC = NULL; - SCpnt->result = DID_NO_CONNECT << 16; + data->CurrentSC = NULL; + SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); - return FAILED; + return FALSE; } //DEBUG(0, __FUNCTION__ "() out\n"); - return SUCCESS; + return TRUE; } /* * setup PIO FIFO transfer mode and enable/disable to data out */ -static void nsp_setup_fifo(unsigned int base, int enabled) +static void nsp_setup_fifo(nsp_hw_data *data, int enabled) { - unsigned char transfer_mode; + unsigned int base = data->BaseAddress; + unsigned char transfer_mode_reg; //DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled); if (enabled != FALSE) { - transfer_mode = TRANSFER_GO | BRAIND; + transfer_mode_reg = TRANSFER_GO | BRAIND; } else { - transfer_mode = 0; + transfer_mode_reg = 0; } - transfer_mode |= nsp_data.TransferMode; + transfer_mode_reg |= data->TransferMode; - nsp_index_write(base, TRANSFERMODE, transfer_mode); + nsp_index_write(base, TRANSFERMODE, transfer_mode_reg); } /* * Initialize Ninja hardware */ -static int nsphw_init(void) +static int nsphw_init(nsp_hw_data *data) { - unsigned int base = nsp_data.BaseAddress; + unsigned int base = data->BaseAddress; int i, j; sync_data tmp_sync = { SyncNegotiation: SYNC_NOT_YET, SyncPeriod: 0, SyncOffset: 0 }; - //DEBUG(0, __FUNCTION__ "() in\n"); + DEBUG(0, __FUNCTION__ "() in base=0x%x\n", base); - nsp_data.ScsiClockDiv = CLOCK_40M; - nsp_data.CurrentSC = NULL; - nsp_data.FifoCount = 0; - nsp_data.TransferMode = MODE_IO8; + data->ScsiClockDiv = CLOCK_40M; + data->CurrentSC = NULL; + data->FifoCount = 0; + data->TransferMode = MODE_IO8; /* setup sync data */ for ( i = 0; i < N_TARGET; i++ ) { for ( j = 0; j < N_LUN; j++ ) { - nsp_data.Sync[i][j] = tmp_sync; + data->Sync[i][j] = tmp_sync; } } @@ -285,7 +291,7 @@ static int nsphw_init(void) nsp_index_write(base, SCSIIRQMODE, 0); nsp_index_write(base, TRANSFERMODE, MODE_IO8); - nsp_index_write(base, CLOCKDIV, nsp_data.ScsiClockDiv); + nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv); nsp_index_write(base, PARITYCTRL, 0); nsp_index_write(base, POINTERCLR, POINTER_CLEAR | @@ -313,7 +319,7 @@ static int nsphw_init(void) SCSI_RESET_IRQ_EI ); nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); - nsp_setup_fifo(base, FALSE); + nsp_setup_fifo(data, FALSE); return TRUE; } @@ -321,7 +327,8 @@ static int nsphw_init(void) /* * Start selection phase */ -static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt) +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, + nsp_hw_data *data) { unsigned int host_id = SCpnt->host->this_id; unsigned int base = SCpnt->host->io_port; @@ -331,7 +338,6 @@ static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt) //DEBUG(0, __FUNCTION__ "()in\n"); - phase = nsp_index_read(base, SCSIBUSMON); if(phase != BUSMON_BUS_FREE) { //DEBUG(0, " bus busy\n"); @@ -371,8 +377,8 @@ static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt) nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); /* check selection timeout */ - nsp_start_timer(SCpnt, 1000/51); - nsp_data.SelectionTimeOut = 1; + nsp_start_timer(SCpnt, data, 1000/51); + data->SelectionTimeOut = 1; return TRUE; } @@ -402,11 +408,11 @@ static struct nsp_sync_table nsp_sync_table_20M[] = { /* * setup synchronous data transfer mode */ -static int nsp_msg(Scsi_Cmnd *SCpnt) +static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data) { unsigned char target = SCpnt->target; unsigned char lun = SCpnt->lun; - sync_data *sync = &(nsp_data.Sync[target][lun]); + sync_data *sync = &(data->Sync[target][lun]); struct nsp_sync_table *sync_table; unsigned int period, offset; int i; @@ -421,7 +427,7 @@ static int nsp_msg(Scsi_Cmnd *SCpnt) DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset); - if (nsp_data.ScsiClockDiv == CLOCK_20M) { + if (data->ScsiClockDiv == CLOCK_20M) { sync_table = &nsp_sync_table_20M[0]; } else { sync_table = &nsp_sync_table_40M[0]; @@ -440,17 +446,19 @@ static int nsp_msg(Scsi_Cmnd *SCpnt) */ DEBUG(0, " no proper period/offset\n"); - sync->SyncPeriod = 0; - sync->SyncOffset = 0; - sync->SyncRegister = 0; - sync->AckWidth = 0; + sync->SyncPeriod = 0; + sync->SyncOffset = 0; + sync->SyncRegister = 0; + sync->AckWidth = 0; + sync->SyncNegotiation = SYNC_OK; return FALSE; } - sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | - (offset & SYNCREG_OFFSET_MASK); - sync->AckWidth = sync_table->ack_width; + sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | + (offset & SYNCREG_OFFSET_MASK); + sync->AckWidth = sync_table->ack_width; + sync->SyncNegotiation = SYNC_OK; DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth); @@ -461,12 +469,12 @@ static int nsp_msg(Scsi_Cmnd *SCpnt) /* * start ninja hardware timer */ -static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time) +static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time) { unsigned int base = SCpnt->host->io_port; //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time); - nsp_data.TimerCount = time; + data->TimerCount = time; nsp_index_write(base, TIMERCOUNT, time); } @@ -535,16 +543,15 @@ static int nsp_expect_signal(Scsi_Cmnd *SCpnt, /* * transfer SCSI message */ -static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) +static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase) { unsigned int base = SCpnt->host->io_port; - char *buf = nsp_data.MsgBuffer; - int len = MIN(MSGBUF_SIZE, nsp_data.MsgLen); + char *buf = data->MsgBuffer; + int len = MIN(MSGBUF_SIZE, data->MsgLen); int ptr; int ret; //DEBUG(0, __FUNCTION__ "()\n"); -/**!**/ for (ptr = 0; len > 0; len --, ptr ++) { ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); @@ -554,16 +561,16 @@ static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) } /* if last byte, negate ATN */ - if (len == 1) { + if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) { nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); } /* read & write message */ if (phase & BUSMON_IO) { - //DEBUG(0, " read msg\n"); + DEBUG(0, " read msg\n"); buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); } else { - //DEBUG(0, " write msg\n"); + DEBUG(0, " write msg\n"); nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); } nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>"); @@ -575,9 +582,8 @@ static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) /* * get extra SCSI data from fifo */ -static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) +static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data) { - unsigned int base = SCpnt->host->io_port; unsigned int count; //DEBUG(0, __FUNCTION__ "()\n"); @@ -587,7 +593,7 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) } count = nsp_fifo_count(SCpnt); - if (nsp_data.FifoCount == count) { + if (data->FifoCount == count) { //DEBUG(0, " not use bypass quirk\n"); return 0; } @@ -597,8 +603,8 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) * data phase skip only occures in case of SCSI_LOW_READ */ SCpnt->SCp.phase = PH_DATA; - nsp_pio_read(SCpnt); - nsp_setup_fifo(base, FALSE); + nsp_pio_read(SCpnt, data); + nsp_setup_fifo(data, FALSE); DEBUG(0, " use bypass quirk\n"); return 0; @@ -607,7 +613,7 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) /* * accept reselection */ -static int nsp_reselected(Scsi_Cmnd *SCpnt) +static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data) { unsigned int base = SCpnt->host->io_port; unsigned char reg; @@ -616,7 +622,7 @@ static int nsp_reselected(Scsi_Cmnd *SCpnt) nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>"); - nsp_nexus(SCpnt); + nsp_nexus(SCpnt, data); reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); nsp_index_write(base, SCSIBUSCTRL, reg); nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB); @@ -653,14 +659,14 @@ static int nsp_fifo_count(Scsi_Cmnd *SCpnt) /* * read data in DATA IN phase */ -static void nsp_pio_read(Scsi_Cmnd *SCpnt) +static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data) { unsigned int base = SCpnt->host->io_port; int time_out, i; int ocount, res; unsigned char stat, fifo_stat; - ocount = nsp_data.FifoCount; + ocount = data->FifoCount; DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); @@ -693,7 +699,7 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt) res = MIN(res, SCpnt->SCp.this_residual); - switch (nsp_data.TransferMode) { + switch (data->TransferMode) { case MODE_IO32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); @@ -725,7 +731,7 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt) time_out = jiffies + 10 * HZ; } - nsp_data.FifoCount = ocount; + data->FifoCount = ocount; if (!i) { printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); @@ -736,16 +742,16 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt) /* * write data in DATA OUT phase */ -static void nsp_pio_write(Scsi_Cmnd *SCpnt) +static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data) { unsigned int base = SCpnt->host->io_port; int time_out, i; unsigned int ocount, res; unsigned char stat; - ocount = nsp_data.FifoCount; + ocount = data->FifoCount; - DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", nsp_data.FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid); + DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID); time_out = jiffies + 10 * HZ; @@ -767,7 +773,7 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt) res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); - switch (nsp_data.TransferMode) { + switch (data->TransferMode) { case MODE_IO32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); @@ -798,7 +804,7 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt) time_out = jiffies + 10 * HZ; } - nsp_data.FifoCount = ocount; + data->FifoCount = ocount; if (!i) { printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID); @@ -812,12 +818,12 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt) /* * setup synchronous/asynchronous data transfer mode */ -static int nsp_nexus(Scsi_Cmnd *SCpnt) +static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data) { - unsigned int base = SCpnt->host->io_port; - unsigned char target = SCpnt->target; - unsigned char lun = SCpnt->lun; - sync_data *sync = &(nsp_data.Sync[target][lun]); + unsigned int base = SCpnt->host->io_port; + unsigned char target = SCpnt->target; + unsigned char lun = SCpnt->lun; + sync_data *sync = &(data->Sync[target][lun]); //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt); @@ -827,16 +833,16 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt) if (RESID % 4 != 0 || RESID <= 256 ) { - nsp_data.TransferMode = MODE_IO8; + data->TransferMode = MODE_IO8; } else { - nsp_data.TransferMode = MODE_IO32; + data->TransferMode = MODE_IO32; } /* setup pdma fifo */ - nsp_setup_fifo(base, TRUE); + nsp_setup_fifo(data, TRUE); /* clear ack counter */ - nsp_data.FifoCount = 0; + data->FifoCount = 0; nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER_CLEAR | REQ_COUNTER_CLEAR | @@ -845,6 +851,7 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt) return 0; } +#include "nsp_message.c" /* * interrupt handler */ @@ -853,13 +860,25 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) unsigned int base; unsigned char i_src, irq_phase, phase; Scsi_Cmnd *tmpSC; - int ret, len; - unsigned char data_reg, control_reg; + int len; + unsigned char target, lun; + unsigned int *sync_neg; + int i, tmp; + nsp_hw_data *data; + //printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id); - //DEBUG(0, __FUNCTION__ "(%d) CurrentSC=0x%p\n", irq, nsp_data.CurrentSC); + /* sanity check */ + if (&nsp_data != dev_id) { + DEBUG(0, " irq conflict? this can't happen\n"); + return; + } + data = dev_id; + if (irq != data->IrqNumber) { + return; + } - base = nsp_data.BaseAddress; + base = data->BaseAddress; //DEBUG(0, " base=0x%x\n", base); /* @@ -891,16 +910,16 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) /* * timer interrupt handler (scsi vs timer interrupts) */ - //DEBUG(0, " timercount=%d\n", nsp_data.TimerCount); - if (nsp_data.TimerCount != 0) { + //DEBUG(0, " timercount=%d\n", data->TimerCount); + if (data->TimerCount != 0) { //DEBUG(0, " stop timer\n"); nsp_index_write(base, TIMERCOUNT, 0); nsp_index_write(base, TIMERCOUNT, 0); - nsp_data.TimerCount = 0; + data->TimerCount = 0; } if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER && - nsp_data.SelectionTimeOut == 0) { + data->SelectionTimeOut == 0) { //DEBUG(0, " timer start\n"); nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); return; @@ -908,11 +927,14 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); - if (nsp_data.CurrentSC == NULL) { + if (data->CurrentSC == NULL) { printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase); return; } else { - tmpSC = nsp_data.CurrentSC; + tmpSC = data->CurrentSC; + target = tmpSC->target; + lun = tmpSC->lun; + sync_neg = &(data->Sync[target][lun].SyncNegotiation); } /* @@ -921,8 +943,8 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) if ((i_src & IRQSTATUS_SCSI) != 0) { if ((irq_phase & SCSI_RESET_IRQ) != 0) { printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n"); - - nsp_data.CurrentSC = NULL; + *sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; tmpSC->result = DID_RESET << 16; tmpSC->scsi_done(tmpSC); return; @@ -931,7 +953,7 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) if ((irq_phase & RESELECT_IRQ) != 0) { DEBUG(0, " reselect\n"); nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); - if (nsp_reselected(tmpSC) != FALSE) { + if (nsp_reselected(tmpSC, data) != FALSE) { return; } } @@ -945,28 +967,29 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) switch(tmpSC->SCp.phase) { case PH_SELSTART: + *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_BSY) == 0) { - //DEBUG(0, " selection count=%d\n", nsp_data.SelectionTimeOut); - if (nsp_data.SelectionTimeOut >= NSP_SELTIMEOUT) { + //DEBUG(0, " selection count=%d\n", data->SelectionTimeOut); + if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { DEBUG(0, " selection time out\n"); - nsp_data.SelectionTimeOut = 0; + data->SelectionTimeOut = 0; nsp_index_write(base, SCSIBUSCTRL, 0); - nsp_data.CurrentSC = NULL; - tmpSC->result = DID_NO_CONNECT << 16; + data->CurrentSC = NULL; + tmpSC->result = DID_NO_CONNECT << 16; tmpSC->scsi_done(tmpSC); return; } - nsp_data.SelectionTimeOut += 1; - nsp_start_timer(tmpSC, 1000/51); + data->SelectionTimeOut += 1; + nsp_start_timer(tmpSC, data, 1000/51); return; } /* attention assert */ //DEBUG(0, " attention assert\n"); - nsp_data.SelectionTimeOut = 0; - tmpSC->SCp.phase = PH_SELECTED; + data->SelectionTimeOut = 0; + tmpSC->SCp.phase = PH_SELECTED; nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); udelay(1); nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); @@ -976,16 +999,17 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) case PH_RESELECT: //DEBUG(0, " phase reselect\n"); + *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { - nsp_data.CurrentSC = NULL; - tmpSC->result = DID_ABORT << 16; + data->CurrentSC = NULL; + tmpSC->result = DID_ABORT << 16; tmpSC->scsi_done(tmpSC); return; } /* fall thru */ default: - if (( i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { + if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { return; } break; @@ -999,8 +1023,9 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) /* normal disconnect */ if ((irq_phase & LATCHED_BUS_FREE) != 0) { //DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); - if ((tmpSC->SCp.Message == 0)) { /* all command complete and return status */ - nsp_data.CurrentSC = NULL; + if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */ + *sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; tmpSC->result = (DID_OK << 16) | (tmpSC->SCp.Message << 8) | (tmpSC->SCp.Status << 0); @@ -1017,8 +1042,9 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) if (phase == 0) { printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); - nsp_data.CurrentSC = NULL; - tmpSC->result = DID_ERROR << 16; + *sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; + tmpSC->result = DID_ERROR << 16; tmpSC->scsi_done(tmpSC); return; } @@ -1033,7 +1059,7 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) tmpSC->SCp.phase = PH_COMMAND; - nsp_nexus(tmpSC); + nsp_nexus(tmpSC, data); /* write scsi command */ nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); @@ -1049,7 +1075,7 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_OUT; - nsp_pio_write(tmpSC); + nsp_pio_write(tmpSC, data); break; @@ -1059,12 +1085,12 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_IN; - nsp_pio_read(tmpSC); + nsp_pio_read(tmpSC, data); break; case BUSPHASE_STATUS: - nsp_dataphase_bypass(tmpSC); + nsp_dataphase_bypass(tmpSC, data); DEBUG(0, " BUSPHASE_STATUS\n"); tmpSC->SCp.phase = PH_STATUS; @@ -1082,78 +1108,64 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) tmpSC->SCp.phase = PH_MSG_OUT; - /* - * XXX: NSP QUIRK - * NSP invoke interrupts only in the case of scsi phase changes, - * therefore we should poll the scsi phase here to catch - * the next "msg out" if exists (no scsi phase changes). - */ - ret = 16; - len = 0; - - nsp_msg(tmpSC); - - nsp_data.MsgBuffer[len] = IDENTIFY(TRUE, tmpSC->lun); len++; - nsp_data.MsgLen = len; - - do { - DEBUG(0, " msgout loop\n"); - - if (nsp_xfer(tmpSC, BUSPHASE_MESSAGE_OUT)) { - printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n"); - } - - /* catch a next signal */ - ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_OUT, BUSMON_REQ); - } while (ret > 0 && len-- > 0); + data->MsgLen = len = 0; + if (*sync_neg == SYNC_NOT_YET) { + data->Sync[target][lun].SyncPeriod = 0; + data->Sync[target][lun].SyncOffset = 0; + nsp_msg(tmpSC, data); + + data->MsgBuffer[len] = IDENTIFY(TRUE, lun); len++; + /* + data->MsgBuffer[len] = MSG_EXTENDED; len++; + data->MsgBuffer[len] = 3; len++; + data->MsgBuffer[len] = MSG_EXT_SDTR; len++; + data->MsgBuffer[len] = 0x0c; len++; + data->MsgBuffer[len] = 15; len++; + */ + } + if (len == 0) { + data->MsgBuffer[len] = MSG_NO_OPERATION; len++; + } + data->MsgLen = len; + show_message(data); + nsp_message_out(tmpSC, data); break; case BUSPHASE_MESSAGE_IN: - nsp_dataphase_bypass(tmpSC); + nsp_dataphase_bypass(tmpSC, data); DEBUG(0, " BUSPHASE_MESSAGE_IN\n"); if ((phase & BUSMON_REQ) == 0) { goto timer_out; } tmpSC->SCp.phase = PH_MSG_IN; + nsp_message_in(tmpSC, data); /* - * XXX: NSP QUIRK - * NSP invoke interrupts only in the case of scsi phase changes, - * therefore we should poll the scsi phase here to catch - * the next "msg in" if exists (no scsi phase changes). - */ - ret = 16; - len = 0; - - do { - //DEBUG(0, " msgin loop\n"); - /* read data */ - data_reg = nsp_index_read(base, SCSIDATAIN); - - /* assert ACK */ - control_reg = nsp_index_read(base, SCSIBUSCTRL); - control_reg |= SCSI_ACK; - nsp_index_write(base, SCSIBUSCTRL, control_reg); - nsp_negate_signal(tmpSC, BUSMON_REQ, "msgin<REQ>"); - - nsp_data.MsgBuffer[len] = data_reg; len++; - DEBUG(0, " msg=0x%x\n", data_reg); - - /* deassert ACK */ - control_reg = nsp_index_read(base, SCSIBUSCTRL); - control_reg &= ~SCSI_ACK; - nsp_index_write(base, SCSIBUSCTRL, control_reg); - - /* catch a next signal */ - ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_IN, BUSMON_REQ); - } while (ret > 0 && MSGBUF_SIZE > len); + if (data->MsgLen >= 5 && + data->MsgBuffer[0] == MSG_EXTENDED && + data->MsgBuffer[1] == 3 && + data->MsgBuffer[2] == MSG_EXT_SDTR ) { + data->Sync[target][lun].SyncPeriod = data->MsgBuffer[3]; + data->Sync[target][lun].SyncOffset = data->MsgBuffer[4]; + nsp_msg(tmpSC, data); + } + */ + + /* search last messeage byte */ + tmp = -1; + for (i = 0; i < data->MsgLen; i++) { + tmp = data->MsgBuffer[i]; + if (data->MsgBuffer[i] == MSG_EXTENDED) { + i += (1 + data->MsgBuffer[i+1]); + } + } + tmpSC->SCp.Message = tmp; - nsp_data.MsgLen = len; - tmpSC->SCp.Message = nsp_data.MsgBuffer[len-1]; + DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen); + show_message(data); - //DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, nsp_data.MsgLen); break; case BUSPHASE_SELECT: @@ -1167,7 +1179,7 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs) return; timer_out: - nsp_start_timer(tmpSC, 1000/102); + nsp_start_timer(tmpSC, data, 1000/102); return; } @@ -1175,6 +1187,136 @@ timer_out: #include "nsp_debug.c" #endif /* DBG_SHOWCOMMAND */ +/*----------------------------------------------------------------*/ +/* look for ninja3 card and init if found */ +/*----------------------------------------------------------------*/ +static int nsp_detect(Scsi_Host_Template *sht) +{ + struct Scsi_Host *host; /* registered host structure */ + nsp_hw_data *data = &nsp_data; + + DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id); + + request_region(data->BaseAddress, data->NumAddress, "nsp_cs"); + host = scsi_register(sht, 0); + host->io_port = data->BaseAddress; + host->unique_id = data->BaseAddress; + host->n_io_port = data->NumAddress; + host->irq = data->IrqNumber; + host->dma_channel = -1; + + sprintf(nspinfo, +/* Buffer size is 100 bytes */ +/* 0 1 2 3 4 5 6 7 8 9 0*/ +/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/ + "NinjaSCSI-3/32Bi Driver version 2.7, I/O 0x%04lx-0x%04lx IRQ %2d", + host->io_port, host->io_port + host->n_io_port, + host->irq); + sht->name = nspinfo; + + DEBUG(0, __FUNCTION__ " end\n"); + + return 1; /* detect done. */ +} + +static int nsp_release(struct Scsi_Host *shpnt) +{ + nsp_hw_data *data = &nsp_data; + + if (shpnt->irq) { + free_irq(shpnt->irq, data); + } + if (shpnt->io_port) { + release_region(shpnt->io_port, shpnt->n_io_port); + } + return 0; +} + +/*----------------------------------------------------------------*/ +/* return info string */ +/*----------------------------------------------------------------*/ +static const char *nsp_info(struct Scsi_Host *shpnt) +{ + return nspinfo; +} + +/*---------------------------------------------------------------*/ +/* error handler */ +/*---------------------------------------------------------------*/ +static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why) +{ + DEBUG(0, __FUNCTION__ " SCpnt=0x%p why=%d\n", SCpnt, why); + + return nsp_eh_bus_reset(SCpnt); +} + +static int nsp_abort(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); + + nsp_eh_bus_reset(SCpnt); + + return SUCCESS; +} + +/*static int nsp_eh_strategy(struct Scsi_Host *Shost) +{ + return FAILED; +}*/ + +static int nsp_eh_abort(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); + + nsp_eh_bus_reset(SCpnt); + return SUCCESS; +} + +static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); + + return FAILED; +} + +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + int i; + + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p base=0x%x\n", SCpnt, base); + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); + mdelay(100); /* 100ms */ + nsp_index_write(base, SCSIBUSCTRL, 0); + for(i = 0; i < 5; i++) { + nsp_index_read(base, IRQPHASESENCE); /* dummy read */ + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + return SUCCESS; +} + +static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt) +{ + nsp_hw_data *data = &nsp_data; + + DEBUG(0, __FUNCTION__ "\n"); + + nsphw_init(data); + nsp_eh_bus_reset(SCpnt); + + return SUCCESS; +} + + +/********************************************************************** + PCMCIA functions + *********************************************************************/ + /*====================================================================*/ static void cs_error(client_handle_t handle, int func, int ret) { @@ -1183,7 +1325,7 @@ static void cs_error(client_handle_t handle, int func, int ret) } /*====================================================================== - nsp_attach() creates an "instance" of the driver, allocating + nsp_cs_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services. @@ -1191,7 +1333,7 @@ static void cs_error(client_handle_t handle, int func, int ret) configure the card at this point -- we wait until we receive a card insertion event. ======================================================================*/ -static dev_link_t *nsp_attach(void) +static dev_link_t *nsp_cs_attach(void) { scsi_info_t *info; client_reg_t client_reg; @@ -1202,13 +1344,13 @@ static dev_link_t *nsp_attach(void) /* Create new SCSI device */ info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; + if (!info) { return NULL; } memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; /* Initialize the dev_link_t structure */ - link->release.function = &nsp_release; + link->release.function = &nsp_cs_release; link->release.data = (u_long)link; /* The io structure describes IO port mapping */ @@ -1227,6 +1369,7 @@ static dev_link_t *nsp_attach(void) } } link->irq.Handler = &nspintr; + link->irq.Instance = &nsp_data; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; @@ -1244,18 +1387,18 @@ static dev_link_t *nsp_attach(void) CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ; - client_reg.event_handler = &nsp_event; + client_reg.event_handler = &nsp_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); - nsp_detach(link); + nsp_cs_detach(link); return NULL; } return link; -} /* nsp_attach */ +} /* nsp_cs_attach */ /*====================================================================== @@ -1264,7 +1407,7 @@ static dev_link_t *nsp_attach(void) structures are freed. Otherwise, the structures will be freed when the device is released. ======================================================================*/ -static void nsp_detach(dev_link_t *link) +static void nsp_cs_detach(dev_link_t *link) { dev_link_t **linkp; @@ -1282,7 +1425,7 @@ static void nsp_detach(dev_link_t *link) del_timer(&link->release); if (link->state & DEV_CONFIG) { - nsp_release((u_long)link); + nsp_cs_release((u_long)link); if (link->state & DEV_STALE_CONFIG) { link->state |= DEV_STALE_LINK; return; @@ -1298,11 +1441,11 @@ static void nsp_detach(dev_link_t *link) *linkp = link->next; kfree(link->priv); -} /* nsp_detach */ +} /* nsp_cs_detach */ /*====================================================================== - nsp_config() is scheduled to run after a CARD_INSERTION event + nsp_cs_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. ======================================================================*/ @@ -1312,7 +1455,7 @@ while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed if (CardServices(fn, args) != 0) goto next_entry /*====================================================================*/ -static void nsp_config(dev_link_t *link) +static void nsp_cs_config(dev_link_t *link) { client_handle_t handle = link->handle; scsi_info_t *info = link->priv; @@ -1324,6 +1467,7 @@ static void nsp_config(dev_link_t *link) Scsi_Device *dev; dev_node_t **tail, *node; struct Scsi_Host *host; + nsp_hw_data *data = &nsp_data; DEBUG(0, __FUNCTION__ "() in\n"); @@ -1369,14 +1513,14 @@ static void nsp_config(dev_link_t *link) release_region(link->io.BasePort1, link->io.NumPorts1); /* Set port and IRQ */ - nsp_data.BaseAddress = link->io.BasePort1; - nsp_data.NumAddress = link->io.NumPorts1; - nsp_data.IrqNumber = link->irq.AssignedIRQ; + data->BaseAddress = link->io.BasePort1; + data->NumAddress = link->io.NumPorts1; + data->IrqNumber = link->irq.AssignedIRQ; DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n", - nsp_data.BaseAddress, nsp_data.NumAddress, nsp_data.IrqNumber); + data->BaseAddress, data->NumAddress, data->IrqNumber); - if(nsphw_init() == FALSE) { + if(nsphw_init(data) == FALSE) { goto cs_failed; } @@ -1446,19 +1590,19 @@ static void nsp_config(dev_link_t *link) cs_failed: cs_error(link->handle, last_fn, last_ret); - nsp_release((u_long)link); + nsp_cs_release((u_long)link); return; -} /* nsp_config */ +} /* nsp_cs_config */ #undef CS_CHECK #undef CFG_CHECK /*====================================================================== - After a card is removed, nsp_release() will unregister the net + After a card is removed, nsp_cs_release() will unregister the net device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ======================================================================*/ -static void nsp_release(u_long arg) +static void nsp_cs_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; @@ -1492,9 +1636,9 @@ static void nsp_release(u_long arg) link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) { - nsp_detach(link); + nsp_cs_detach(link); } -} /* nsp_release */ +} /* nsp_cs_release */ /*====================================================================== @@ -1509,7 +1653,7 @@ static void nsp_release(u_long arg) the card is still present. ======================================================================*/ -static int nsp_event(event_t event, +static int nsp_cs_event(event_t event, int priority, event_callback_args_t *args) { @@ -1532,7 +1676,7 @@ static int nsp_event(event_t event, DEBUG(0, " event: insert\n"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; info->bus = args->bus; - nsp_config(link); + nsp_cs_config(link); break; case CS_EVENT_PM_SUSPEND: @@ -1556,11 +1700,9 @@ static int nsp_event(event_t event, CardServices(RequestConfiguration, link->handle, &link->conf); tmp.host = info->host; - nsp_reset(&tmp, 0); + nsp_eh_host_reset(&tmp); } info->stop = 0; - /* restart IO */ - nsphw_init(); break; default: @@ -1569,110 +1711,12 @@ static int nsp_event(event_t event, } DEBUG(0, __FUNCTION__ " end\n"); return 0; -} /* nsp_event */ - -/*----------------------------------------------------------------*/ -/* look for ninja3 card and init if found */ -/*----------------------------------------------------------------*/ -static int nsp_detect(Scsi_Host_Template *sht) -{ - struct Scsi_Host *host; /* registered host structure */ - - DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id); - -#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE) - sht->proc_dir = &proc_scsi_nsp; /* kernel 2.2 */ -#else - sht->proc_name = "nsp_cs"; /* kernel 2.4 */ -#endif - - sht->this_id = SCSI_INITIATOR_ID; - - request_region(nsp_data.BaseAddress, nsp_data.NumAddress,"nsp_cs"); - host = scsi_register(sht, 0); - host->io_port = nsp_data.BaseAddress; - host->unique_id = nsp_data.BaseAddress; - host->n_io_port = nsp_data.NumAddress; - host->irq = nsp_data.IrqNumber; - host->dma_channel = -1; - - sprintf(nspinfo, -/* Buffer size is 100 bytes */ -/* 0 1 2 3 4 5 6 7 8 9 0*/ -/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/ - "NinjaSCSI-3/32Bi Driver version 2.0, I/O 0x%04lx-0x%04lx IRQ %2d", - host->io_port, host->io_port + host->n_io_port, - host->irq); - sht->name = nspinfo; - - DEBUG(0, __FUNCTION__ " end\n"); - - return 1; /* detect done. */ -} - - -/*----------------------------------------------------------------*/ -/* return info string */ -/*----------------------------------------------------------------*/ -static const char *nsp_info(struct Scsi_Host *host) -{ - return nspinfo; -} - -static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why) -{ - DEBUG(0, __FUNCTION__ "() SCpnt=0x%p why=%d\n", SCpnt, why); - - return nsp_eh_bus_reset(SCpnt); -} - -static int nsp_abort(Scsi_Cmnd *SCpnt) -{ - DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt); - return FAILED; -} - -/*static int nsp_eh_strategy(struct Scsi_Host *Shost) -{ -} -static int nsp_eh_abort(Scsi_Cmnd * cmd) -{ - DEBUG(0, __FUNCTION__"() SCpnt\n"); -} - -static nsp_eh_device_reset(Scsi_Cmnd *) -{ -} -*/ -static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) -{ - unsigned int base = SCpnt->host->io_port; - int i; - - DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt); - - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); - - nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); - mdelay(100); /* 100ms */ - nsp_index_write(base, SCSIBUSCTRL, 0); - for(i = 0; i < 5; i++) { - (void) nsp_index_read(base, IRQPHASESENCE); /* dummy read */ - } - - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); - - return 0; -} -/* -static nsp_eh_host_reset(Scsi_Cmnd *) -{ -}*/ +} /* nsp_cs_event */ /*======================================================================* * module entry point *====================================================================*/ -static int __init nsp_init(void) +static int __init nsp_cs_init(void) { servinfo_t serv; @@ -1684,27 +1728,27 @@ static int __init nsp_init(void) "does not match!\n"); return -1; } - register_pcmcia_driver(&dev_info, &nsp_attach, &nsp_detach); + register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach); DEBUG(0, __FUNCTION__ "() out\n"); return 0; } -static void __exit nsp_cleanup(void) +static void __exit nsp_cs_cleanup(void) { - DEBUG(0, "nsp_cs: unloading\n"); + DEBUG(0, __FUNCTION__ "() unloading\n"); unregister_pcmcia_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) { - nsp_release((u_long)dev_list); + nsp_cs_release((u_long)dev_list); } - nsp_detach(dev_list); + nsp_cs_detach(dev_list); } } -module_init(nsp_init); -module_exit(nsp_cleanup); +module_init(nsp_cs_init); +module_exit(nsp_cs_cleanup); /* * diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index b6309f935fac..610ccfdecac8 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -6,11 +6,11 @@ Ver 0.1 : Initial version. This software may be used and distributed according to the terms of - the GNU General Public License. + the GNU Public License. =========================================================*/ -/* $Id: nsp_cs.h,v 1.18 2001/02/09 04:42:19 elca Exp $ */ +/* $Id: nsp_cs.h,v 1.21 2001/07/04 14:45:31 elca Exp $ */ #ifndef __nsp_cs__ #define __nsp_cs__ @@ -38,6 +38,8 @@ /* SCSI initiator must be 7 */ #define SCSI_INITIATOR_ID 7 +#define NSP_SELTIMEOUT 200 + /* base register */ #define IRQCONTROL 0x00 # define IRQCONTROL_RESELECT_CLEAR BIT(0) @@ -239,9 +241,9 @@ typedef struct _nsp_data { Scsi_Cmnd *CurrentSC; int FifoCount; -#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) int Residual; -#define RESID nsp_data.Residual +#define RESID data->Residual #else #define RESID SCpnt->resid #endif @@ -256,21 +258,30 @@ typedef struct _nsp_data { } nsp_hw_data; -static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt); -static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time); +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, nsp_hw_data *data); +static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time); +static int nsp_eh_abort(Scsi_Cmnd * SCpnt); +static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt); static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt); +static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt); static int nsp_fifo_count(Scsi_Cmnd *SCpnt); -static void nsp_pio_read(Scsi_Cmnd *SCpnt); -static int nsp_nexus(Scsi_Cmnd *SCpnt); +static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data); +static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data); #ifdef PCMCIA_DEBUG # ifdef DBG_SHOWCOMMAND static void show_command(Scsi_Cmnd *ptr); static void show_phase(Scsi_Cmnd *SCpnt); static void show_busphase(unsigned char stat); +static void show_message(nsp_hw_data *data); # endif /* DBG_SHOWCOMMAND */ +#else +# define show_command(ptr) /* */ +# define show_phase(SCpnt) /* */ +# define show_busphase(stat) /* */ +# define show_message(data) /* */ #endif /* @@ -297,6 +308,11 @@ enum _data_in_out { }; -#define NSP_SELTIMEOUT 200 +/* SCSI messaage */ +#define MSG_COMMAND_COMPLETE 0x00 +#define MSG_EXTENDED 0x01 +#define MSG_NO_OPERATION 0x08 + +#define MSG_EXT_SDTR 0x01 #endif /*__nsp_cs__*/ diff --git a/drivers/scsi/pcmcia/nsp_debug.c b/drivers/scsi/pcmcia/nsp_debug.c index 328f545894d8..4c72343c04d7 100644 --- a/drivers/scsi/pcmcia/nsp_debug.c +++ b/drivers/scsi/pcmcia/nsp_debug.c @@ -3,10 +3,10 @@ By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> This software may be used and distributed according to the terms of - the GNU General Public License. + the GNU Public License. =========================================================================*/ -/* $Id: nsp_debug.c,v 1.5 2001/02/08 08:08:58 elca Exp $ */ +/* $Id: nsp_debug.c,v 1.6 2001/07/04 14:43:53 elca Exp $ */ /* * Show the command data of a command @@ -193,3 +193,16 @@ static void show_busphase(unsigned char stat) break; } } + +static void show_message(nsp_hw_data *data) +{ + int i; + + printk(KERN_DEBUG "msg:"); + for(i=0; i < data->MsgLen; i++) { + printk(" %02x", data->MsgBuffer[i]); + } + printk("\n"); +} + +/* end */ diff --git a/drivers/scsi/pcmcia/nsp_io.h b/drivers/scsi/pcmcia/nsp_io.h index 21156e516db9..a26358dd56b2 100644 --- a/drivers/scsi/pcmcia/nsp_io.h +++ b/drivers/scsi/pcmcia/nsp_io.h @@ -3,7 +3,7 @@ By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> This software may be used and distributed according to the terms of - the GNU General Public License. + the GNU Public License. */ diff --git a/drivers/scsi/pcmcia/nsp_message.c b/drivers/scsi/pcmcia/nsp_message.c new file mode 100644 index 000000000000..6385bfbc8fa0 --- /dev/null +++ b/drivers/scsi/pcmcia/nsp_message.c @@ -0,0 +1,76 @@ +/*========================================================================== + NinjaSCSI-3 message handler + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + This software may be used and distributed according to the terms of + the GNU Public License. + */ + +/* $Id: nsp_message.c,v 1.6 2001/07/05 10:56:37 elca Exp $ */ + +static void nsp_message_in(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->host->io_port; + unsigned char data_reg, control_reg; + int ret, len; + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg in" if exists (no scsi phase changes). + */ + ret = 16; + len = 0; + + DEBUG(0, " msgin loop\n"); + do { + /* read data */ + data_reg = nsp_index_read(base, SCSIDATAIN); + + /* assert ACK */ + control_reg = nsp_index_read(base, SCSIBUSCTRL); + control_reg |= SCSI_ACK; + nsp_index_write(base, SCSIBUSCTRL, control_reg); + nsp_negate_signal(SCpnt, BUSMON_REQ, "msgin<REQ>"); + + data->MsgBuffer[len] = data_reg; len++; + + /* deassert ACK */ + control_reg = nsp_index_read(base, SCSIBUSCTRL); + control_reg &= ~SCSI_ACK; + nsp_index_write(base, SCSIBUSCTRL, control_reg); + + /* catch a next signal */ + ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_IN, BUSMON_REQ); + } while (ret > 0 && MSGBUF_SIZE > len); + + data->MsgLen = len; + +} + +static void nsp_message_out(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + int ret = 1; + int len = data->MsgLen; + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg out" if exists (no scsi phase changes). + */ + + DEBUG(0, " msgout loop\n"); + do { + if (nsp_xfer(SCpnt, data, BUSPHASE_MESSAGE_OUT)) { + printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n"); + } + + /* catch a next signal */ + ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_OUT, BUSMON_REQ); + } while (ret > 0 && len-- > 0); + +} + +/* end */ diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 3bf203c8dada..56774a5b9049 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -1337,21 +1337,10 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } - switch (Cmnd->cmnd[0]) { - case TEST_UNIT_READY: - case START_STOP: - break; - case WRITE_10: - case WRITE_6: - case WRITE_BUFFER: - case MODE_SELECT: + if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) cmd->control_flags = cpu_to_le16(CFLAG_WRITE); - break; - default: + else cmd->control_flags = cpu_to_le16(CFLAG_READ); - break; - } - if (Cmnd->device->tagged_supported) { if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) { @@ -1870,6 +1859,11 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) hostdata = (struct isp2x00_hostdata *) host->hostdata; + /* + * This cannot be right - PCI writes are posted + * (apparently this is hardware design flaw not software ?) + */ + outw(0x01, host->io_port + ISP_CTRL_STATUS); udelay(100); outw(HCCR_RESET, host->io_port + HOST_HCCR); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 749f6f445c4a..57f1817c1443 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -762,8 +762,17 @@ static int sd_init_onedisk(int i) */ SRpnt = scsi_allocate_request(rscsi_disks[i].device); + if (!SRpnt) { + printk(KERN_WARNING "(sd_init_onedisk:) Request allocation failure.\n"); + return i; + } buffer = (unsigned char *) scsi_malloc(512); + if (!buffer) { + printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation failure.\n"); + scsi_release_request(SRpnt); + return i; + } spintime = 0; diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c index 0985f01df3e8..9a6d8395b6af 100644 --- a/drivers/usb/usbkbd.c +++ b/drivers/usb/usbkbd.c @@ -1,7 +1,7 @@ /* - * $Id: usbkbd.c,v 1.16 2000/08/14 21:05:26 vojtech Exp $ + * $Id: usbkbd.c,v 1.20 2001/04/26 08:34:49 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Keyboard support * @@ -249,7 +249,7 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum, input_register_device(&kbd->dev); - printk(KERN_INFO "input%d: %s on on usb%d:%d.%d\n", + printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum); return kbd; diff --git a/fs/buffer.c b/fs/buffer.c index 6b2702b00b75..e2ccafa93f79 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -194,16 +194,20 @@ static void write_locked_buffers(struct buffer_head **array, unsigned int count) } while (--count); } +/* + * Write some buffers from the head of the dirty queue. + * + * This must be called with the LRU lock held, and will + * return without it! + */ #define NRSYNC (32) -static void write_unlocked_buffers(kdev_t dev) +static int write_some_buffers(kdev_t dev) { struct buffer_head *next; struct buffer_head *array[NRSYNC]; unsigned int count; int nr; -repeat: - spin_lock(&lru_list_lock); next = lru_list[BUF_DIRTY]; nr = nr_buffers_type[BUF_DIRTY] * 2; count = 0; @@ -224,7 +228,7 @@ repeat: spin_unlock(&lru_list_lock); write_locked_buffers(array, count); - goto repeat; + return -EAGAIN; } unlock_buffer(bh); put_bh(bh); @@ -233,6 +237,18 @@ repeat: if (count) write_locked_buffers(array, count); + return 0; +} + +/* + * Write out all buffers on the dirty list. + */ +static void write_unlocked_buffers(kdev_t dev) +{ + do { + spin_lock(&lru_list_lock); + } while (write_some_buffers(dev)); + run_task_queue(&tq_disk); } static int wait_for_locked_buffers(kdev_t dev, int index, int refile) @@ -767,7 +783,7 @@ static void refill_freelist(int size) if (free_shortage()) page_launder(GFP_NOFS, 0); if (!grow_buffers(size)) { - wakeup_bdflush(1); + wakeup_bdflush(); current->policy |= SCHED_YIELD; __set_current_state(TASK_RUNNING); schedule(); @@ -1078,7 +1094,19 @@ void balance_dirty(kdev_t dev) if (state < 0) return; - wakeup_bdflush(state); + wakeup_bdflush(); + + /* + * If we're getting a lot out of balance, start some IO ourselves. + * + * This only queues it, and does not actually start it - we'll let + * bdflush do that, or let it happen as a result of a lot of calls + * to balance_dirty() filling up the request queues. + */ + if (state > 0) { + spin_lock(&lru_list_lock); + write_some_buffers(dev); + } } static __inline__ void __mark_dirty(struct buffer_head *bh) @@ -2400,7 +2428,7 @@ busy_buffer_page: loop = 1; goto cleaned_buffers_try_again; } - wakeup_bdflush(0); + wakeup_bdflush(); } return 0; } @@ -2524,69 +2552,11 @@ void __init buffer_init(unsigned long mempages) * a limited number of buffers to the disks and then go back to sleep again. */ -/* This is the _only_ function that deals with flushing async writes - to disk. - NOTENOTENOTENOTE: we _only_ need to browse the DIRTY lru list - as all dirty buffers lives _only_ in the DIRTY lru list. - As we never browse the LOCKED and CLEAN lru lists they are infact - completly useless. */ -static int flush_dirty_buffers(int check_flushtime) -{ - struct buffer_head * bh, *next; - int flushed = 0, i; - - restart: - spin_lock(&lru_list_lock); - bh = lru_list[BUF_DIRTY]; - if (!bh) - goto out_unlock; - for (i = nr_buffers_type[BUF_DIRTY]; i-- > 0; bh = next) { - next = bh->b_next_free; - - if (!buffer_dirty(bh)) { - __refile_buffer(bh); - continue; - } - if (buffer_locked(bh)) - continue; - - if (check_flushtime) { - /* The dirty lru list is chronologically ordered so - if the current bh is not yet timed out, - then also all the following bhs - will be too young. */ - if (time_before(jiffies, bh->b_flushtime)) - goto out_unlock; - } else { - if (++flushed > bdf_prm.b_un.ndirty) - goto out_unlock; - } - - /* OK, now we are committed to write it out. */ - get_bh(bh); - spin_unlock(&lru_list_lock); - ll_rw_block(WRITE, 1, &bh); - put_bh(bh); - - if (current->need_resched) - schedule(); - goto restart; - } - out_unlock: - spin_unlock(&lru_list_lock); - - return flushed; -} - DECLARE_WAIT_QUEUE_HEAD(bdflush_wait); -void wakeup_bdflush(int block) +void wakeup_bdflush(void) { - if (waitqueue_active(&bdflush_wait)) - wake_up_interruptible(&bdflush_wait); - - if (block) - flush_dirty_buffers(0); + wake_up_interruptible(&bdflush_wait); } /* @@ -2604,10 +2574,20 @@ static int sync_old_buffers(void) sync_supers(0); unlock_kernel(); - flush_dirty_buffers(1); - /* must really sync all the active I/O request to disk here */ - run_task_queue(&tq_disk); - return 0; + spin_lock(&lru_list_lock); + for (;;) { + if (write_some_buffers(NODEV)) { + struct buffer_head *bh; + + spin_lock(&lru_list_lock); + bh = lru_list[BUF_DIRTY]; + if (!time_before(jiffies, bh->b_flushtime)) + continue; + spin_unlock(&lru_list_lock); + } + run_task_queue(&tq_disk); + return 0; + } } int block_sync_page(struct page *page) @@ -2677,7 +2657,7 @@ asmlinkage long sys_bdflush(int func, long data) int bdflush(void *startup) { struct task_struct *tsk = current; - int flushed; + /* * We have a bare-bones task_struct, and really should fill * in a few more things so "top" and /proc/2/{exe,root,cwd} @@ -2700,14 +2680,8 @@ int bdflush(void *startup) for (;;) { CHECK_EMERGENCY_SYNC - flushed = flush_dirty_buffers(0); - - /* - * If there are still a lot of dirty buffers around, - * skip the sleep and flush some more. Otherwise, we - * go to sleep waiting a wakeup. - */ - if (!flushed || balance_dirty_state(NODEV) < 0) { + spin_lock(&lru_list_lock); + if (!write_some_buffers(NODEV) || balance_dirty_state(NODEV) < 0) { run_task_queue(&tq_disk); interruptible_sleep_on(&bdflush_wait); } diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 40a05ce1ad10..89ef2495affc 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -77,11 +77,23 @@ static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_s }; /* + * This is ucking fugly but its probably the best thing for 2.4.x + * Take it as a clear reminder than we should put the device name + * generation in the object kdev_t points to in 2.5. + */ + +#ifdef CONFIG_ARCH_S390 +int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; +EXPORT_SYMBOL(genhd_dasd_name); +#endif + +/* * disk_name() is used by partition check code and the md driver. * It formats the devicename of the indicated disk into * the supplied buffer (of size at least 32), and returns * a pointer to that same buffer (for convenience). */ + char *disk_name (struct gendisk *hd, int minor, char *buf) { unsigned int part; @@ -96,6 +108,12 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) if (pos >= 0) return buf + pos; } + +#ifdef CONFIG_ARCH_S390 + if (genhd_dasd_name + && genhd_dasd_name (buf, unit - 'a', part, hd) == 0) + return buf; +#endif /* * IDE devices use multiple major numbers, but the drives * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index f5b3d7430ab9..dac6bfa3fe82 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -10,14 +10,14 @@ * 02/13/00 VTOC partition support added */ -#include <linux/module.h> +#include <linux/config.h> #include <linux/fs.h> #include <linux/genhd.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/string.h> #include <linux/blk.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/hdreg.h> #include <linux/ioctl.h> #include <linux/version.h> @@ -29,14 +29,6 @@ #include "check.h" #include <asm/vtoc.h> -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -/* We hook in when DASD is a module... */ -int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; -int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL; -EXPORT_SYMBOL(genhd_dasd_fillgeo); -EXPORT_SYMBOL(genhd_dasd_name); -#endif /* LINUX_IS_24 */ - typedef enum { ibm_partition_lnx1 = 0, ibm_partition_vol1 = 1, @@ -50,6 +42,73 @@ static char* part_names[] = { [ibm_partition_lnx1] = "LNX1", [ibm_partition_none] = "(nonl)" }; +static int +get_drive_geometry(int kdev,struct hd_geometry *geo) +{ + int rc = 0; + mm_segment_t old_fs; + struct file *filp; + struct inode *inode; + /* find out offset of volume label (partn table) */ + filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL); + if ( filp == NULL ) { + printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo +r filp\n"); + return -ENOMEM; + } + memset(filp,0,sizeof(struct file)); + filp ->f_mode = 1; /* read only */ + inode = get_empty_inode(); + if ( inode == NULL ) + return -ENOMEM; + inode -> i_rdev = kdev; + inode -> i_bdev = bdget(kdev_t_to_nr(kdev)); + rc = blkdev_open(inode,filp); + if ( rc == 0 ) { + old_fs=get_fs(); + set_fs(KERNEL_DS); + rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, + (unsigned long)(geo)) + ; + set_fs(old_fs); + } + blkdev_put(inode->i_bdev,BDEV_FILE); + return rc; +} + +static int +get_drive_info(int kdev,dasd_information_t *info) +{ + int rc = 0; + mm_segment_t old_fs; + struct file *filp; + struct inode *inode; + /* find out offset of volume label (partn table) */ + filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL); + if ( filp == NULL ) { + printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo +r filp\n"); + return -ENOMEM; + } + memset(filp,0,sizeof(struct file)); + filp ->f_mode = 1; /* read only */ + inode = get_empty_inode(); + if ( inode == NULL ) + return -ENOMEM; + inode -> i_rdev = kdev; + inode -> i_bdev = bdget(kdev_t_to_nr(kdev)); + rc = blkdev_open(inode,filp); + if ( rc == 0 ) { + old_fs=get_fs(); + set_fs(KERNEL_DS); + rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, BIODASDINFO, + (unsigned long)(info)); + set_fs(old_fs); + } + blkdev_put(inode->i_bdev,BDEV_FILE); + return rc; +} + static ibm_partition_t get_partition_type ( char * type ) { @@ -110,38 +169,52 @@ first_part_minor) ibm_partition_t partition_type; char type[5] = {0,}; char name[7] = {0,}; - struct hd_geometry geo; + struct hd_geometry *geo; int blocksize; int offset=0, size=0, psize=0, counter=0; unsigned int blk; format1_label_t f1; volume_label_t vlabel; + dasd_information_t *info; if ( first_sector != 0 ) { BUG(); } - if ( !genhd_dasd_fillgeo ) { + info = (struct dasd_information_t *)kmalloc(sizeof(dasd_information_t), + GFP_KERNEL); + if ( info == NULL ) + return 0; + if (get_drive_info (dev,info)) + return 0; + geo = (struct hd_geometry *)kmalloc(sizeof(struct hd_geometry), + GFP_KERNEL); + if ( geo == NULL ) + return 0; + if (get_drive_geometry (dev,geo)) return 0; - } - genhd_dasd_fillgeo(dev,&geo); blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; if ( blocksize <= 0 ) { return 0; } - + set_blocksize(dev, blocksize); /* OUCH !! */ - if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) { + if ( ( bh = bread( dev, info->label_block, blocksize) ) != NULL ) { strncpy ( type,bh -> b_data + 0, 4); - strncpy ( name,bh -> b_data + 4, 6); + if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) { + + strncpy ( name,bh -> b_data + 8, 6); + } else { + strncpy ( name,bh -> b_data + 4, 6); + } memcpy (&vlabel, bh->b_data, sizeof(volume_label_t)); } else { return 0; } EBCASC(type,4); EBCASC(name,6); - + partition_type = get_partition_type(type); - printk ( "%6s/%6s:",part_names[partition_type],name); + printk ( "%4s/%8s:",part_names[partition_type],name); switch ( partition_type ) { case ibm_partition_cms1: if (* (((long *)bh->b_data) + 13) != 0) { @@ -152,38 +225,37 @@ first_part_minor) size = (label[7]-1)*(blocksize>>9); printk ("(MDSK)"); } else { - offset = (geo.start + 1); + offset = (info->label_block + 1); size = hd -> sizes[MINOR(dev)]<<1; } - two_partitions( hd, MINOR(dev), blocksize, - offset, size); + two_partitions( hd, MINOR(dev), blocksize, offset, size); break; case ibm_partition_lnx1: case ibm_partition_none: - offset = (geo.start + 1); + offset = (info->label_block + 1); size = hd -> sizes[MINOR(dev)]<<1; - two_partitions( hd, MINOR(dev), blocksize, - offset, size); + two_partitions( hd, MINOR(dev), blocksize, offset, size); break; - case ibm_partition_vol1: + case ibm_partition_vol1: + size = hd -> sizes[MINOR(dev)]<<1; add_gd_partition(hd, MINOR(dev), 0, size); - + /* get block number and read then first format1 label */ - blk = cchhb2blk(&vlabel.vtoc, &geo) + 1; + blk = cchhb2blk(&vlabel.vtoc, geo) + 1; if ((buf = bread( dev, blk, blocksize)) != NULL) { memcpy (&f1, buf->b_data, sizeof(format1_label_t)); bforget(buf); } - + while (f1.DS1FMTID == _ascebc['1']) { - offset = cchh2blk(&f1.DS1EXT1.llimit, &geo); - psize = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - - offset + 1; + offset = cchh2blk(&f1.DS1EXT1.llimit, geo); + psize = cchh2blk(&f1.DS1EXT1.ulimit, geo) - + offset + geo->sectors; counter++; add_gd_partition(hd, MINOR(dev) + counter, - offset * (blocksize >> 9), - psize * (blocksize >> 9)); + offset * (blocksize >> 9), + psize * (blocksize >> 9)); blk++; if ((buf = bread( dev, blk, blocksize)) != NULL) { @@ -197,9 +269,8 @@ first_part_minor) add_gd_partition( hd, MINOR(dev), 0, 0); add_gd_partition( hd, MINOR(dev) + 1, 0, 0); } - + printk ( "\n" ); bforget(bh); return 1; } - diff --git a/fs/read_write.c b/fs/read_write.c index 2d264640c901..ff3a86cc8596 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -15,6 +15,7 @@ #include <asm/uaccess.h> struct file_operations generic_ro_fops = { + llseek: generic_file_llseek, read: generic_file_read, mmap: generic_file_mmap, }; @@ -24,6 +25,34 @@ ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos) return -EISDIR; } +loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) +{ + long long retval; + + switch (origin) { + case 2: + offset += file->f_dentry->d_inode->i_size; + break; + case 1: + offset += file->f_pos; + } + retval = -EINVAL; + if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) { + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + retval = offset; + } + return retval; +} + +loff_t no_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + loff_t default_llseek(struct file *file, loff_t offset, int origin) { long long retval; diff --git a/include/asm-i386/serial.h b/include/asm-i386/serial.h index 33cd30fc9a6d..ecc8278676ed 100644 --- a/include/asm-i386/serial.h +++ b/include/asm-i386/serial.h @@ -31,7 +31,9 @@ #else #define RS_TABLE_SIZE #endif - + +#define MCA_COM_FLAGS (STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA) + /* * The following define the access methods for the HUB6 card. All * access is through two ports for all 24 possible chips. The card is @@ -113,12 +115,12 @@ #ifdef CONFIG_MCA #define MCA_SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS }, \ - { 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS }, + { 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS }, \ + { 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS }, #else #define MCA_SERIAL_PORT_DFNS #endif diff --git a/include/asm-s390/cache.h b/include/asm-s390/cache.h index 93565f5e0191..ae5338ec5064 100644 --- a/include/asm-s390/cache.h +++ b/include/asm-s390/cache.h @@ -12,6 +12,6 @@ #define __ARCH_S390_CACHE_H #define L1_CACHE_BYTES 256 -#define L1_CACHE_SHIFT 16 +#define L1_CACHE_SHIFT 8 #endif diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h index 3bde842ce288..f9ee1d530e48 100644 --- a/include/asm-s390/dasd.h +++ b/include/asm-s390/dasd.h @@ -4,43 +4,39 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * + * This file is the interface of the DASD device driver, which is exported to user space + * any future changes wrt the API will result in a change of the APIVERSION reported + * to userspace by the DASDAPIVER-ioctl + * * History of changes (starts July 2000) - * 02/01/01 added dynamic registration of ioctls + * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h */ #ifndef DASD_H #define DASD_H - -#undef ERP_DEBUG /* enable debug messages */ -#undef ERP_FULL_ERP /* enable full ERP - experimental code !!!! */ -#define CONFIG_DASD_DYNAMIC - #include <linux/ioctl.h> -#include <asm/irq.h> -#define IOCTL_LETTER 'D' -/* Disable the volume (for Linux) */ -#define BIODASDDISABLE _IO(IOCTL_LETTER,0) -/* Enable the volume (for Linux) */ -#define BIODASDENABLE _IO(IOCTL_LETTER,1) -/* Issue a reserve/release command, rsp. */ -#define BIODASDRSRV _IO(IOCTL_LETTER,2) /* reserve */ -#define BIODASDRLSE _IO(IOCTL_LETTER,3) /* release */ -#define BIODASDSLCK _IO(IOCTL_LETTER,4) /* steal lock */ -/* Read sense ID infpormation */ -#define BIODASDRSID _IOR(IOCTL_LETTER,0,senseid_t) -/* Format the volume or an extent */ -#define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) -/* translate blocknumber of partition to absolute */ -#define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) +#define DASD_IOCTL_LETTER 'D' -typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args); -int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler); -int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler); +#if (DASD_API_VERSION == 0) -#define DASD_NAME "dasd" #define DASD_PARTN_BITS 2 -#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) + +/* + * struct profile_info_t + * holds the profinling information + */ +typedef struct dasd_profile_info_t { + unsigned int dasd_io_reqs; /* number of requests processed at all */ + unsigned int dasd_io_sects; /* number of sectors processed at all */ + unsigned int dasd_io_secs[32]; /* histogram of request's sizes */ + unsigned int dasd_io_times[32]; /* histogram of requests's times */ + unsigned int dasd_io_timps[32]; /* histogram of requests's times per sector */ + unsigned int dasd_io_time1[32]; /* histogram of time from build to start */ + unsigned int dasd_io_time2[32]; /* histogram of time from start to irq */ + unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */ + unsigned int dasd_io_time3[32]; /* histogram of time from irq to end */ +} dasd_profile_info_t; /* * struct format_data_t @@ -50,332 +46,65 @@ typedef struct format_data_t { int start_unit; /* from track */ int stop_unit; /* to track */ int blksize; /* sectorsize */ - int intensity; /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */ -} __attribute__ ((packed)) format_data_t; - -#define DASD_FORMAT_DEFAULT_START_UNIT 0 -#define DASD_FORMAT_DEFAULT_STOP_UNIT -1 -#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 -#define DASD_FORMAT_DEFAULT_INTENSITY -1 - -#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 -#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 -#define DASD_FORMAT_INTENS_INVALIDATE 0x04 -#define DASD_FORMAT_INTENS_CDL 0x08 -#ifdef __KERNEL__ -#include <linux/version.h> -#include <linux/major.h> -#include <linux/wait.h> -#include <asm/ccwcache.h> -#include <linux/blk.h> -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -#include <linux/blkdev.h> -#include <linux/devfs_fs_kernel.h> -#endif -#include <linux/genhd.h> -#include <linux/hdreg.h> -#include <linux/compatmac.h> - -#include <asm/s390dyn.h> -#include <asm/todclk.h> -#include <asm/debug.h> - -/* Kernel Version Compatibility section */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) -typedef struct request *request_queue_t; -#define block_device_operations file_operations -#define __setup(x,y) struct dasd_device_t -#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops) -#define register_disk(dd,dev,partn,ops,size) \ -do { \ - dd->sizes[MINOR(dev)] = size >> 1; \ - resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \ -} while(0) -#define init_waitqueue_head(x) do { *x = NULL; } while(0) -#define blk_cleanup_queue(x) do {} while(0) -#define blk_init_queue(x...) do {} while(0) -#define blk_queue_headactive(x...) do {} while(0) -#define blk_queue_make_request(x) do {} while(0) -#define list_empty(x) (0) -#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ -do { \ - blk_dev[d_major].request_fn = d_request_fn; \ - blk_dev[d_major].queue = d_queue_fn; \ - blk_dev[d_major].current_request = d_current; \ -} while(0) -#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ - major:D_MAJOR, \ - major_name:D_NAME, \ - minor_shift:D_PARTN_BITS, \ - max_p:1 << D_PARTN_BITS, \ - max_nr:D_PER_MAJOR, \ - nr_real:D_PER_MAJOR, -static inline struct request * -dasd_next_request( request_queue_t *queue ) -{ - return *queue; -} -static inline void -dasd_dequeue_request( request_queue_t * q, struct request *req ) -{ - *q = req->next; - req->next = NULL; -} -#else -#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ -do { \ - blk_dev[d_major].queue = d_queue_fn; \ -} while(0) -#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ - major:D_MAJOR, \ - major_name:D_NAME, \ - minor_shift:D_PARTN_BITS, \ - max_p:1 << D_PARTN_BITS, \ - nr_real:D_PER_MAJOR, -static inline struct request * -dasd_next_request( request_queue_t *queue ) -{ - return blkdev_entry_next_request(&queue->queue_head); -} -static inline void -dasd_dequeue_request( request_queue_t * q, struct request *req ) -{ - blkdev_dequeue_request (req); -} -#endif - -/* dasd_range_t are used for dynamic device att-/detachment */ -typedef struct dasd_devreg_t { - devreg_t devreg; /* the devreg itself */ - /* build a linked list of devregs, needed for cleanup */ - struct list_head list; -} dasd_devreg_t; - -typedef struct { - struct list_head list; - int no; - dasd_ioctl_fn_t handler; -} dasd_ioctl_list_t; - -typedef enum { - dasd_era_fatal = -1, /* no chance to recover */ - dasd_era_none = 0, /* don't recover, everything alright */ - dasd_era_msg = 1, /* don't recover, just report... */ - dasd_era_recover = 2 /* recovery action recommended */ -} dasd_era_t; - -/* BIT DEFINITIONS FOR SENSE DATA */ -#define DASD_SENSE_BIT_0 0x80 -#define DASD_SENSE_BIT_1 0x40 -#define DASD_SENSE_BIT_2 0x20 -#define DASD_SENSE_BIT_3 0x10 - -#define check_then_set(where,from,to) \ -do { \ - if ((*(where)) != (from) ) { \ - printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \ - BUG(); \ - } \ - (*(where)) = (to); \ -} while (0) - -#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ -do { \ - int d_devno = d_device->devinfo.devno; \ - int d_irq = d_device->devinfo.irq; \ - char *d_name = d_device->name; \ - int d_major = MAJOR(d_device->kdev); \ - int d_minor = MINOR(d_device->kdev); \ - printk(d_loglevel PRINTK_HEADER \ - "/dev/%s(%d:%d),%04X IRQ0x%x:" \ - d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ -} while(0) - -/* - * struct dasd_sizes_t - * represents all data needed to access dasd with properly set up sectors - */ -typedef -struct dasd_sizes_t { - unsigned long blocks; /* size of volume in blocks */ - unsigned int bp_block; /* bytes per block */ - unsigned int s2b_shift; /* log2 (bp_block/512) */ - unsigned int pt_block; /* from which block to read the partn table */ -} dasd_sizes_t; + int intensity; +} format_data_t; -/* - * struct dasd_chanq_t - * represents a queue of channel programs related to a single device +/* + * values to be used for format_data_t.intensity + * 0/8: normal format + * 1/9: also write record zero + * 3/11: also write home address + * 4/12: invalidate track */ -typedef -struct dasd_chanq_t { - ccw_req_t *head; - ccw_req_t *tail; -} dasd_chanq_t; - -#define DASD_DEVICE_FORMAT_STRING "Device: %p" -#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\ -do {\ - if ( d_device->debug_area != NULL )\ - debug_sprintf_event(d_device->debug_area,d_level,\ - DASD_DEVICE_FORMAT_STRING d_str "\n",\ - d_device, d_data);\ -} while(0); -#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ -do {\ - if ( d_device->debug_area != NULL )\ - debug_sprintf_exception(d_device->debug_area,d_level,\ - DASD_DEVICE_FORMAT_STRING d_str "\n",\ - d_device, d_data);\ -} while(0); - -#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" -#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ -do {\ - if ( dasd_debug_area != NULL )\ - debug_sprintf_event(dasd_debug_area, d_level,\ - DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ - d_fn, d_data);\ -} while(0); -#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ -do {\ - if ( dasd_debug_area != NULL )\ - debug_sprintf_exception(dasd_debug_area, d_level,\ - DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ - d_fn, d_data);\ -} while(0); - -struct dasd_device_t; -struct request; +#define DASD_FMT_INT_FMT_R0 1 /* write record zero */ +#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */ +#define DASD_FMT_INT_INVAL 4 /* invalidate tracks */ +#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */ /* - * signatures for the functions of dasd_discipline_t - * make typecasts much easier + * struct dasd_information_t + * represents any data about the data, which is visible to userspace */ -typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); -typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); - -typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *); -typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); -typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *); -typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *); -typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *); -typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *); -typedef int (*dasd_io_starter_fn_t) (ccw_req_t *); -typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *); -typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat); -typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *); -typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *); -typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *); -typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *); -typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *); -typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *); -typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *); - - -/* - * the dasd_discipline_t is - * sth like a table of virtual functions, if you think of dasd_eckd - * inheriting dasd... - * no, currently we are not planning to reimplement the driver in C++ - */ -typedef struct dasd_discipline_t { - char ebcname[8]; /* a name used for tagging and printks */ - char name[8]; /* a name used for tagging and printks */ - int max_blocks; /* maximum number of blocks to be chained */ - dasd_ck_id_fn_t id_check; /* to check sense data */ - dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ - dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ - dasd_do_analysis_fn_t do_analysis; /* to complete the analysis of the volume */ - dasd_fill_geometry_fn_t fill_geometry; /* to set up hd_geometry */ - dasd_io_starter_fn_t start_IO; - dasd_format_fn_t format_device; /* to format the device */ - dasd_error_examine_fn_t examine_error; - dasd_error_analyse_fn_t erp_action; - dasd_erp_analyse_fn_t erp_postaction; - dasd_cp_builder_fn_t build_cp_from_req; - dasd_dump_sense_fn_t dump_sense; - dasd_int_handler_fn_t int_handler; - dasd_reserve_fn_t reserve; - dasd_release_fn_t release; - dasd_merge_cp_fn_t merge_cp; - - struct dasd_discipline_t *next; /* used for list of disciplines */ -} dasd_discipline_t; - -#define DASD_MAJOR_INFO_REGISTERED 1 -#define DASD_MAJOR_INFO_IS_STATIC 2 - -typedef struct major_info_t { - struct list_head list; - struct dasd_device_t **dasd_device; - int flags; - struct gendisk gendisk; /* actually contains the major number */ -} __attribute__ ((packed)) major_info_t; - -typedef struct dasd_profile_info_t { - unsigned long dasd_io_reqs; /* number of requests processed at all */ - unsigned long dasd_io_secs[32]; /* histogram of request's sizes */ - unsigned long dasd_io_times[32]; /* histogram of requests's times */ - unsigned long dasd_io_timps[32]; /* histogram of requests's times per sector */ - unsigned long dasd_io_time1[32]; /* histogram of time from build to start */ - unsigned long dasd_io_time2[32]; /* histogram of time from start to irq */ - unsigned long dasd_io_time2ps[32]; /* histogram of time from start to irq */ - unsigned long dasd_io_time3[32]; /* histogram of time from irq to end */ -} dasd_profile_info_t; - -typedef struct dasd_device_t { - s390_dev_info_t devinfo; - dasd_discipline_t *discipline; - int level; - int open_count; - kdev_t kdev; - major_info_t *major_info; - struct dasd_chanq_t queue; - wait_queue_head_t wait_q; - request_queue_t request_queue; - struct timer_list timer; - devstat_t dev_status; /* needed ONLY!! for request_irq */ - dasd_sizes_t sizes; - char name[16]; /* The name of the device in /dev */ - char *private; /* to be used by the discipline internally */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - devfs_handle_t devfs_entry; -#endif /* LINUX_IS_24 */ - struct tq_struct bh_tq; - atomic_t bh_scheduled; - debug_info_t *debug_area; - dasd_profile_info_t profile; - struct proc_dir_entry *proc_dir; /* directory node */ - struct proc_dir_entry *proc_info; /* information from dasd_device_t */ - struct proc_dir_entry *proc_stats; /* statictics information */ -} dasd_device_t; - -/* dasd_device_t.level can be: */ -#define DASD_DEVICE_LEVEL_UNKNOWN 0x00 -#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01 -#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 -#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 -#define DASD_DEVICE_LEVEL_ANALYSED 0x08 -#define DASD_DEVICE_LEVEL_ONLINE 0x10 - -int dasd_init (void); -void dasd_discipline_enq (dasd_discipline_t *); -int dasd_discipline_deq(dasd_discipline_t *); -int dasd_start_IO (ccw_req_t *); -void dasd_int_handler (int , void *, struct pt_regs *); -ccw_req_t *default_erp_action (ccw_req_t *); -ccw_req_t *default_erp_postaction (ccw_req_t *); -int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); -ccw_req_t *dasd_alloc_request (char *, int, int); -void dasd_free_request (ccw_req_t *); -extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); -extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *); -int dasd_oper_handler (int irq, devreg_t * devreg); -void dasd_schedule_bh (dasd_device_t *); - -#endif /* __KERNEL__ */ +typedef struct dasd_information_t { + unsigned int devno; /* S/390 devno */ + unsigned int real_devno; /* for aliases */ + unsigned int schid; /* S/390 subchannel identifier */ + unsigned int cu_type : 16; /* from SenseID */ + unsigned int cu_model : 8; /* from SenseID */ + unsigned int dev_type : 16; /* from SenseID */ + unsigned int dev_model : 8; /* from SenseID */ + unsigned int open_count; + unsigned int req_queue_len; + unsigned int chanq_len; + char type[4]; /* from discipline.name, 'none' for unknown */ + unsigned int status; /* current device level */ + unsigned int label_block; /* where to find the VOLSER */ + unsigned int FBA_layout; /* fixed block size (like AIXVOL) */ + unsigned int characteristics_size; + unsigned int confdata_size; + char characteristics[64]; /* from read_device_characteristics */ + char configuration_data[256]; /* from read_configuration_data */ +} dasd_information_t; +/* Disable the volume (for Linux) */ +#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) +/* Enable the volume (for Linux) */ +#define BIODASDENABLE _IO(DASD_IOCTL_LETTER,1) +/* Issue a reserve/release command, rsp. */ +#define BIODASDRSRV _IO(DASD_IOCTL_LETTER,2) /* reserve */ +#define BIODASDRLSE _IO(DASD_IOCTL_LETTER,3) /* release */ +#define BIODASDSLCK _IO(DASD_IOCTL_LETTER,4) /* steal lock */ +/* reset profiling information of a device */ +#define BIODASDPRRST _IO(DASD_IOCTL_LETTER,5) +/* retrieve API version number */ +#define DASDAPIVER _IOR(DASD_IOCTL_LETTER,0,int) +/* Get information on a dasd device */ +#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t) +/* retrieve profiling information of a device */ +#define BIODASDPRRD _IOR(DASD_IOCTL_LETTER,2,dasd_profile_info_t) +/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ +#define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t) +#endif /* DASD_API_VERSION */ #endif /* DASD_H */ /* diff --git a/include/asm-s390/vtoc.h b/include/asm-s390/vtoc.h index 2f53faaa6728..4a7927896ed5 100644 --- a/include/asm-s390/vtoc.h +++ b/include/asm-s390/vtoc.h @@ -15,41 +15,188 @@ #include <linux/types.h> #include <linux/hdreg.h> #include <linux/version.h> -#endif #include <asm/dasd.h> +#endif + +#define DASD_API_VERSION 0 #define LINE_LENGTH 80 #define VTOC_START_CC 0x0 #define VTOC_START_HH 0x1 +#define FIRST_USABLE_CYL 1 +#define FIRST_USABLE_TRK 2 + +#define DASD_3380_TYPE 13148 +#define DASD_3390_TYPE 13200 +#define DASD_9345_TYPE 37701 + +#define DASD_3380_VALUE 0xbb60 +#define DASD_3390_VALUE 0xe5a2 +#define DASD_9345_VALUE 0xbc98 + +#define VOLSER_LENGTH 6 +#define BIG_DISK_SIZE 0x10000 + +#define VTOC_ERROR "VTOC error:" enum failure {unable_to_open, unable_to_seek, unable_to_write, unable_to_read}; -typedef struct ttr { +unsigned char ASCtoEBC[256] = +{ + /*00 NL SH SX EX ET NQ AK BL */ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + /*08 BS HT LF VT FF CR SO SI */ + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /*10 DL D1 D2 D3 D4 NK SN EB */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26, + /*18 CN EM SB EC FS GS RS US */ + 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, + /*20 SP ! " # $ % & ' */ + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + /*28 ( ) * + , - . / */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + /*30 0 1 2 3 4 5 6 7 */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /*38 8 9 : ; < = > ? */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + /*40 @ A B C D E F G */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /*48 H I J K L M N O */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + /*50 P Q R S T U V W */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + /*58 X Y Z [ \ ] ^ _ */ + 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, + /*60 ` a b c d e f g */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + /*68 h i j k l m n o */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*70 p q r s t u v w */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + /*78 x y z { | } ~ DL */ + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF +}; + + +unsigned char EBCtoASC[256] = +{ + /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC + -ENP ->LF */ + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB + -IUS */ + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC + -INP */ + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL + -SW */ + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + /* 0x40 SP RSP ä ---- */ + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + /* 0x48 . < ( + | */ + 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + /* 0x50 & ---- */ + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + /* 0x58 ß ! $ * ) ; */ + 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, + /* 0x60 - / ---- Ä ---- ---- ---- */ + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + /* 0x68 ---- , % _ > ? */ + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x78 * ` : # @ ' = " */ + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + /* 0x80 * a b c d e f g */ + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + /* 0x88 h i ---- ---- ---- */ + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + /* 0x90 ° j k l m n o p */ + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + /* 0x98 q r ---- ---- */ + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + /* 0xA0 ~ s t u v w x */ + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + /* 0xA8 y z ---- ---- ---- ---- */ + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + /* 0xB0 ^ ---- § ---- */ + 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + /* 0xB8 ---- [ ] ---- ---- ---- ---- */ + 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, + /* 0xC0 { A B C D E F G */ + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + /* 0xC8 H I ---- ö ---- */ + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + /* 0xD0 } J K L M N O P */ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + /* 0xD8 Q R ---- ü */ + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + /* 0xE0 \ S T U V W X */ + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + /* 0xE8 Y Z ---- Ö ---- ---- ---- */ + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + /* 0xF0 0 1 2 3 4 5 6 7 */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 +}; + +typedef struct ttr +{ __u16 tt; __u8 r; } __attribute__ ((packed)) ttr_t; -typedef struct cchhb { +typedef struct cchhb +{ __u16 cc; __u16 hh; __u8 b; } __attribute__ ((packed)) cchhb_t; -typedef struct cchh { +typedef struct cchh +{ __u16 cc; __u16 hh; } __attribute__ ((packed)) cchh_t; -typedef struct labeldate { +typedef struct labeldate +{ __u8 year; __u16 day; } __attribute__ ((packed)) labeldate_t; -typedef struct volume_label { +typedef struct volume_label +{ char volkey[4]; /* volume key = volume label */ char vollbl[4]; /* volume label */ char volid[6]; /* volume identifier */ @@ -66,7 +213,8 @@ typedef struct volume_label { } __attribute__ ((packed)) volume_label_t; -typedef struct extent { +typedef struct extent +{ __u8 typeind; /* extent type indicator */ __u8 seqno; /* extent sequence number */ cchh_t llimit; /* starting point of this extent */ @@ -74,7 +222,8 @@ typedef struct extent { } __attribute__ ((packed)) extent_t; -typedef struct dev_const { +typedef struct dev_const +{ __u16 DS4DSCYL; /* number of logical cyls */ __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ __u16 DS4DEVTK; /* device track length */ @@ -88,7 +237,8 @@ typedef struct dev_const { } __attribute__ ((packed)) dev_const_t; -typedef struct format1_label { +typedef struct format1_label +{ char DS1DSNAM[44]; /* data set name */ __u8 DS1FMTID; /* format identifier */ char DS1DSSN[6]; /* data set serial number */ @@ -124,7 +274,8 @@ typedef struct format1_label { } __attribute__ ((packed)) format1_label_t; -typedef struct format4_label { +typedef struct format4_label +{ char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ __u8 DS4IDFMT; /* format identifier */ cchhb_t DS4HPCHR; /* highest address of a format 1 DSCB */ @@ -153,6 +304,43 @@ typedef struct format4_label { } __attribute__ ((packed)) format4_label_t; +typedef struct ds5ext +{ + __u16 t; /* RTA of the first track of free extent */ + __u16 fc; /* number of whole cylinders in free ext. */ + __u8 ft; /* number of remaining free tracks */ +} __attribute__ ((packed)) ds5ext_t; + + +typedef struct format5_label +{ + char DS5KEYID[4]; /* key identifier */ + ds5ext_t DS5AVEXT; /* first available (free-space) extent. */ + ds5ext_t DS5EXTAV[7]; /* seven available extents */ + __u8 DS5FMTID; /* format identifier */ + ds5ext_t DS5MAVET[18]; /* eighteen available extents */ + cchhb_t DS5PTRDS[5]; /* pointer to next format5 DSCB */ +} __attribute__ ((packed)) format5_label_t; + + +typedef struct ds7ext +{ + __u32 a; /* starting RTA value */ + __u32 b; /* ending RTA value + 1 */ +} __attribute__ ((packed)) ds7ext_t; + + +typedef struct format7_label +{ + char DS7KEYID[4]; /* key identifier */ + ds7ext_t DS7EXTNT[5]; /* space for 5 extent descriptions */ + __u8 DS7FMTID; /* format identifier */ + ds7ext_t DS7ADEXT[11]; /* space for 11 extent descriptions */ + char res1[2]; /* reserved */ + cchhb_t DS7PTRDS; /* pointer to next FMT7 DSCB */ +} __attribute__ ((packed)) format7_label_t; + + char * vtoc_ebcdic_enc ( unsigned char source[LINE_LENGTH], unsigned char target[LINE_LENGTH], @@ -181,45 +369,126 @@ void vtoc_set_date ( __u8 year, __u16 day); +void vtoc_volume_label_init ( + volume_label_t *vlabel); int vtoc_read_volume_label ( char * device, unsigned long vlabel_start, volume_label_t * vlabel); + int vtoc_write_volume_label ( - char * device, + char *device, unsigned long vlabel_start, - volume_label_t * vlabel); + volume_label_t *vlabel); + +void vtoc_volume_label_set_volser ( + volume_label_t *vlabel, + char *volser); + +char *vtoc_volume_label_get_volser ( + volume_label_t *vlabel, + char *volser); + +void vtoc_volume_label_set_key ( + volume_label_t *vlabel, + char *key); + +void vtoc_volume_label_set_label ( + volume_label_t *vlabel, + char *lbl); + +char *vtoc_volume_label_get_label ( + volume_label_t *vlabel, + char *lbl); + void vtoc_read_label ( char *device, unsigned long position, + format1_label_t *f1, format4_label_t *f4, - format1_label_t *f1); + format5_label_t *f5, + format7_label_t *f7); + void vtoc_write_label ( char *device, unsigned long position, + format1_label_t *f1, format4_label_t *f4, - format1_label_t *f1); -void vtoc_init_format4_label ( - struct hd_geometry *geo, - format4_label_t *f4lbl, - unsigned int usable_partitions, - unsigned int cylinders, - unsigned int tracks, - unsigned int blocks); + format5_label_t *f5, + format7_label_t *f7); + + void vtoc_init_format1_label ( char *volid, unsigned int blksize, extent_t *part_extent, format1_label_t *f1); -void vtoc_update_format4_label ( - format4_label_t *f4, - cchhb_t *highest_f1, - __u8 unused_update, - __u16 freespace_update); +void vtoc_init_format4_label ( + format4_label_t *f4lbl, + unsigned int usable_partitions, + unsigned int cylinders, + unsigned int tracks, + unsigned int blocks, + unsigned int blksize, + __u16 dev_type); +void vtoc_update_format4_label ( + format4_label_t *f4, + cchhb_t *highest_f1, + __u16 unused_update); + + +void vtoc_init_format5_label ( + format5_label_t *f5); + +void vtoc_update_format5_label_add ( + format5_label_t *f5, + int verbose, + int cyl, + int trk, + __u16 a, + __u16 b, + __u8 c); + +void vtoc_update_format5_label_del ( + format5_label_t *f5, + int verbose, + int cyl, + int trk, + __u16 a, + __u16 b, + __u8 c); + + +void vtoc_init_format7_label ( + format7_label_t *f7); + +void vtoc_update_format7_label_add ( + format7_label_t *f7, + int verbose, + __u32 a, + __u32 b); + +void vtoc_update_format7_label_del ( + format7_label_t *f7, + int verbose, + __u32 a, + __u32 b); + + +void vtoc_set_freespace( + format4_label_t *f4, + format5_label_t *f5, + format7_label_t *f7, + char ch, + int verbose, + __u32 start, + __u32 stop, + int cyl, + int trk); diff --git a/include/asm-s390x/cache.h b/include/asm-s390x/cache.h index 93565f5e0191..ae5338ec5064 100644 --- a/include/asm-s390x/cache.h +++ b/include/asm-s390x/cache.h @@ -12,6 +12,6 @@ #define __ARCH_S390_CACHE_H #define L1_CACHE_BYTES 256 -#define L1_CACHE_SHIFT 16 +#define L1_CACHE_SHIFT 8 #endif diff --git a/include/asm-s390x/dasd.h b/include/asm-s390x/dasd.h index 3bde842ce288..f9ee1d530e48 100644 --- a/include/asm-s390x/dasd.h +++ b/include/asm-s390x/dasd.h @@ -4,43 +4,39 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * + * This file is the interface of the DASD device driver, which is exported to user space + * any future changes wrt the API will result in a change of the APIVERSION reported + * to userspace by the DASDAPIVER-ioctl + * * History of changes (starts July 2000) - * 02/01/01 added dynamic registration of ioctls + * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h */ #ifndef DASD_H #define DASD_H - -#undef ERP_DEBUG /* enable debug messages */ -#undef ERP_FULL_ERP /* enable full ERP - experimental code !!!! */ -#define CONFIG_DASD_DYNAMIC - #include <linux/ioctl.h> -#include <asm/irq.h> -#define IOCTL_LETTER 'D' -/* Disable the volume (for Linux) */ -#define BIODASDDISABLE _IO(IOCTL_LETTER,0) -/* Enable the volume (for Linux) */ -#define BIODASDENABLE _IO(IOCTL_LETTER,1) -/* Issue a reserve/release command, rsp. */ -#define BIODASDRSRV _IO(IOCTL_LETTER,2) /* reserve */ -#define BIODASDRLSE _IO(IOCTL_LETTER,3) /* release */ -#define BIODASDSLCK _IO(IOCTL_LETTER,4) /* steal lock */ -/* Read sense ID infpormation */ -#define BIODASDRSID _IOR(IOCTL_LETTER,0,senseid_t) -/* Format the volume or an extent */ -#define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) -/* translate blocknumber of partition to absolute */ -#define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) +#define DASD_IOCTL_LETTER 'D' -typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args); -int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler); -int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler); +#if (DASD_API_VERSION == 0) -#define DASD_NAME "dasd" #define DASD_PARTN_BITS 2 -#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) + +/* + * struct profile_info_t + * holds the profinling information + */ +typedef struct dasd_profile_info_t { + unsigned int dasd_io_reqs; /* number of requests processed at all */ + unsigned int dasd_io_sects; /* number of sectors processed at all */ + unsigned int dasd_io_secs[32]; /* histogram of request's sizes */ + unsigned int dasd_io_times[32]; /* histogram of requests's times */ + unsigned int dasd_io_timps[32]; /* histogram of requests's times per sector */ + unsigned int dasd_io_time1[32]; /* histogram of time from build to start */ + unsigned int dasd_io_time2[32]; /* histogram of time from start to irq */ + unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */ + unsigned int dasd_io_time3[32]; /* histogram of time from irq to end */ +} dasd_profile_info_t; /* * struct format_data_t @@ -50,332 +46,65 @@ typedef struct format_data_t { int start_unit; /* from track */ int stop_unit; /* to track */ int blksize; /* sectorsize */ - int intensity; /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */ -} __attribute__ ((packed)) format_data_t; - -#define DASD_FORMAT_DEFAULT_START_UNIT 0 -#define DASD_FORMAT_DEFAULT_STOP_UNIT -1 -#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 -#define DASD_FORMAT_DEFAULT_INTENSITY -1 - -#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01 -#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02 -#define DASD_FORMAT_INTENS_INVALIDATE 0x04 -#define DASD_FORMAT_INTENS_CDL 0x08 -#ifdef __KERNEL__ -#include <linux/version.h> -#include <linux/major.h> -#include <linux/wait.h> -#include <asm/ccwcache.h> -#include <linux/blk.h> -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -#include <linux/blkdev.h> -#include <linux/devfs_fs_kernel.h> -#endif -#include <linux/genhd.h> -#include <linux/hdreg.h> -#include <linux/compatmac.h> - -#include <asm/s390dyn.h> -#include <asm/todclk.h> -#include <asm/debug.h> - -/* Kernel Version Compatibility section */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) -typedef struct request *request_queue_t; -#define block_device_operations file_operations -#define __setup(x,y) struct dasd_device_t -#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops) -#define register_disk(dd,dev,partn,ops,size) \ -do { \ - dd->sizes[MINOR(dev)] = size >> 1; \ - resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \ -} while(0) -#define init_waitqueue_head(x) do { *x = NULL; } while(0) -#define blk_cleanup_queue(x) do {} while(0) -#define blk_init_queue(x...) do {} while(0) -#define blk_queue_headactive(x...) do {} while(0) -#define blk_queue_make_request(x) do {} while(0) -#define list_empty(x) (0) -#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ -do { \ - blk_dev[d_major].request_fn = d_request_fn; \ - blk_dev[d_major].queue = d_queue_fn; \ - blk_dev[d_major].current_request = d_current; \ -} while(0) -#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ - major:D_MAJOR, \ - major_name:D_NAME, \ - minor_shift:D_PARTN_BITS, \ - max_p:1 << D_PARTN_BITS, \ - max_nr:D_PER_MAJOR, \ - nr_real:D_PER_MAJOR, -static inline struct request * -dasd_next_request( request_queue_t *queue ) -{ - return *queue; -} -static inline void -dasd_dequeue_request( request_queue_t * q, struct request *req ) -{ - *q = req->next; - req->next = NULL; -} -#else -#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ -do { \ - blk_dev[d_major].queue = d_queue_fn; \ -} while(0) -#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ - major:D_MAJOR, \ - major_name:D_NAME, \ - minor_shift:D_PARTN_BITS, \ - max_p:1 << D_PARTN_BITS, \ - nr_real:D_PER_MAJOR, -static inline struct request * -dasd_next_request( request_queue_t *queue ) -{ - return blkdev_entry_next_request(&queue->queue_head); -} -static inline void -dasd_dequeue_request( request_queue_t * q, struct request *req ) -{ - blkdev_dequeue_request (req); -} -#endif - -/* dasd_range_t are used for dynamic device att-/detachment */ -typedef struct dasd_devreg_t { - devreg_t devreg; /* the devreg itself */ - /* build a linked list of devregs, needed for cleanup */ - struct list_head list; -} dasd_devreg_t; - -typedef struct { - struct list_head list; - int no; - dasd_ioctl_fn_t handler; -} dasd_ioctl_list_t; - -typedef enum { - dasd_era_fatal = -1, /* no chance to recover */ - dasd_era_none = 0, /* don't recover, everything alright */ - dasd_era_msg = 1, /* don't recover, just report... */ - dasd_era_recover = 2 /* recovery action recommended */ -} dasd_era_t; - -/* BIT DEFINITIONS FOR SENSE DATA */ -#define DASD_SENSE_BIT_0 0x80 -#define DASD_SENSE_BIT_1 0x40 -#define DASD_SENSE_BIT_2 0x20 -#define DASD_SENSE_BIT_3 0x10 - -#define check_then_set(where,from,to) \ -do { \ - if ((*(where)) != (from) ) { \ - printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \ - BUG(); \ - } \ - (*(where)) = (to); \ -} while (0) - -#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ -do { \ - int d_devno = d_device->devinfo.devno; \ - int d_irq = d_device->devinfo.irq; \ - char *d_name = d_device->name; \ - int d_major = MAJOR(d_device->kdev); \ - int d_minor = MINOR(d_device->kdev); \ - printk(d_loglevel PRINTK_HEADER \ - "/dev/%s(%d:%d),%04X IRQ0x%x:" \ - d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ -} while(0) - -/* - * struct dasd_sizes_t - * represents all data needed to access dasd with properly set up sectors - */ -typedef -struct dasd_sizes_t { - unsigned long blocks; /* size of volume in blocks */ - unsigned int bp_block; /* bytes per block */ - unsigned int s2b_shift; /* log2 (bp_block/512) */ - unsigned int pt_block; /* from which block to read the partn table */ -} dasd_sizes_t; + int intensity; +} format_data_t; -/* - * struct dasd_chanq_t - * represents a queue of channel programs related to a single device +/* + * values to be used for format_data_t.intensity + * 0/8: normal format + * 1/9: also write record zero + * 3/11: also write home address + * 4/12: invalidate track */ -typedef -struct dasd_chanq_t { - ccw_req_t *head; - ccw_req_t *tail; -} dasd_chanq_t; - -#define DASD_DEVICE_FORMAT_STRING "Device: %p" -#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\ -do {\ - if ( d_device->debug_area != NULL )\ - debug_sprintf_event(d_device->debug_area,d_level,\ - DASD_DEVICE_FORMAT_STRING d_str "\n",\ - d_device, d_data);\ -} while(0); -#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ -do {\ - if ( d_device->debug_area != NULL )\ - debug_sprintf_exception(d_device->debug_area,d_level,\ - DASD_DEVICE_FORMAT_STRING d_str "\n",\ - d_device, d_data);\ -} while(0); - -#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" -#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ -do {\ - if ( dasd_debug_area != NULL )\ - debug_sprintf_event(dasd_debug_area, d_level,\ - DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ - d_fn, d_data);\ -} while(0); -#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ -do {\ - if ( dasd_debug_area != NULL )\ - debug_sprintf_exception(dasd_debug_area, d_level,\ - DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ - d_fn, d_data);\ -} while(0); - -struct dasd_device_t; -struct request; +#define DASD_FMT_INT_FMT_R0 1 /* write record zero */ +#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */ +#define DASD_FMT_INT_INVAL 4 /* invalidate tracks */ +#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */ /* - * signatures for the functions of dasd_discipline_t - * make typecasts much easier + * struct dasd_information_t + * represents any data about the data, which is visible to userspace */ -typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); -typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); - -typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *); -typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); -typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *); -typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *); -typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *); -typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *); -typedef int (*dasd_io_starter_fn_t) (ccw_req_t *); -typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *); -typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat); -typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *); -typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *); -typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *); -typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *); -typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *); -typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *); -typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *); - - -/* - * the dasd_discipline_t is - * sth like a table of virtual functions, if you think of dasd_eckd - * inheriting dasd... - * no, currently we are not planning to reimplement the driver in C++ - */ -typedef struct dasd_discipline_t { - char ebcname[8]; /* a name used for tagging and printks */ - char name[8]; /* a name used for tagging and printks */ - int max_blocks; /* maximum number of blocks to be chained */ - dasd_ck_id_fn_t id_check; /* to check sense data */ - dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ - dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ - dasd_do_analysis_fn_t do_analysis; /* to complete the analysis of the volume */ - dasd_fill_geometry_fn_t fill_geometry; /* to set up hd_geometry */ - dasd_io_starter_fn_t start_IO; - dasd_format_fn_t format_device; /* to format the device */ - dasd_error_examine_fn_t examine_error; - dasd_error_analyse_fn_t erp_action; - dasd_erp_analyse_fn_t erp_postaction; - dasd_cp_builder_fn_t build_cp_from_req; - dasd_dump_sense_fn_t dump_sense; - dasd_int_handler_fn_t int_handler; - dasd_reserve_fn_t reserve; - dasd_release_fn_t release; - dasd_merge_cp_fn_t merge_cp; - - struct dasd_discipline_t *next; /* used for list of disciplines */ -} dasd_discipline_t; - -#define DASD_MAJOR_INFO_REGISTERED 1 -#define DASD_MAJOR_INFO_IS_STATIC 2 - -typedef struct major_info_t { - struct list_head list; - struct dasd_device_t **dasd_device; - int flags; - struct gendisk gendisk; /* actually contains the major number */ -} __attribute__ ((packed)) major_info_t; - -typedef struct dasd_profile_info_t { - unsigned long dasd_io_reqs; /* number of requests processed at all */ - unsigned long dasd_io_secs[32]; /* histogram of request's sizes */ - unsigned long dasd_io_times[32]; /* histogram of requests's times */ - unsigned long dasd_io_timps[32]; /* histogram of requests's times per sector */ - unsigned long dasd_io_time1[32]; /* histogram of time from build to start */ - unsigned long dasd_io_time2[32]; /* histogram of time from start to irq */ - unsigned long dasd_io_time2ps[32]; /* histogram of time from start to irq */ - unsigned long dasd_io_time3[32]; /* histogram of time from irq to end */ -} dasd_profile_info_t; - -typedef struct dasd_device_t { - s390_dev_info_t devinfo; - dasd_discipline_t *discipline; - int level; - int open_count; - kdev_t kdev; - major_info_t *major_info; - struct dasd_chanq_t queue; - wait_queue_head_t wait_q; - request_queue_t request_queue; - struct timer_list timer; - devstat_t dev_status; /* needed ONLY!! for request_irq */ - dasd_sizes_t sizes; - char name[16]; /* The name of the device in /dev */ - char *private; /* to be used by the discipline internally */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - devfs_handle_t devfs_entry; -#endif /* LINUX_IS_24 */ - struct tq_struct bh_tq; - atomic_t bh_scheduled; - debug_info_t *debug_area; - dasd_profile_info_t profile; - struct proc_dir_entry *proc_dir; /* directory node */ - struct proc_dir_entry *proc_info; /* information from dasd_device_t */ - struct proc_dir_entry *proc_stats; /* statictics information */ -} dasd_device_t; - -/* dasd_device_t.level can be: */ -#define DASD_DEVICE_LEVEL_UNKNOWN 0x00 -#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01 -#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 -#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 -#define DASD_DEVICE_LEVEL_ANALYSED 0x08 -#define DASD_DEVICE_LEVEL_ONLINE 0x10 - -int dasd_init (void); -void dasd_discipline_enq (dasd_discipline_t *); -int dasd_discipline_deq(dasd_discipline_t *); -int dasd_start_IO (ccw_req_t *); -void dasd_int_handler (int , void *, struct pt_regs *); -ccw_req_t *default_erp_action (ccw_req_t *); -ccw_req_t *default_erp_postaction (ccw_req_t *); -int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); -ccw_req_t *dasd_alloc_request (char *, int, int); -void dasd_free_request (ccw_req_t *); -extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); -extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *); -int dasd_oper_handler (int irq, devreg_t * devreg); -void dasd_schedule_bh (dasd_device_t *); - -#endif /* __KERNEL__ */ +typedef struct dasd_information_t { + unsigned int devno; /* S/390 devno */ + unsigned int real_devno; /* for aliases */ + unsigned int schid; /* S/390 subchannel identifier */ + unsigned int cu_type : 16; /* from SenseID */ + unsigned int cu_model : 8; /* from SenseID */ + unsigned int dev_type : 16; /* from SenseID */ + unsigned int dev_model : 8; /* from SenseID */ + unsigned int open_count; + unsigned int req_queue_len; + unsigned int chanq_len; + char type[4]; /* from discipline.name, 'none' for unknown */ + unsigned int status; /* current device level */ + unsigned int label_block; /* where to find the VOLSER */ + unsigned int FBA_layout; /* fixed block size (like AIXVOL) */ + unsigned int characteristics_size; + unsigned int confdata_size; + char characteristics[64]; /* from read_device_characteristics */ + char configuration_data[256]; /* from read_configuration_data */ +} dasd_information_t; +/* Disable the volume (for Linux) */ +#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) +/* Enable the volume (for Linux) */ +#define BIODASDENABLE _IO(DASD_IOCTL_LETTER,1) +/* Issue a reserve/release command, rsp. */ +#define BIODASDRSRV _IO(DASD_IOCTL_LETTER,2) /* reserve */ +#define BIODASDRLSE _IO(DASD_IOCTL_LETTER,3) /* release */ +#define BIODASDSLCK _IO(DASD_IOCTL_LETTER,4) /* steal lock */ +/* reset profiling information of a device */ +#define BIODASDPRRST _IO(DASD_IOCTL_LETTER,5) +/* retrieve API version number */ +#define DASDAPIVER _IOR(DASD_IOCTL_LETTER,0,int) +/* Get information on a dasd device */ +#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t) +/* retrieve profiling information of a device */ +#define BIODASDPRRD _IOR(DASD_IOCTL_LETTER,2,dasd_profile_info_t) +/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ +#define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t) +#endif /* DASD_API_VERSION */ #endif /* DASD_H */ /* diff --git a/include/asm-s390x/vtoc.h b/include/asm-s390x/vtoc.h index 2f53faaa6728..4a7927896ed5 100644 --- a/include/asm-s390x/vtoc.h +++ b/include/asm-s390x/vtoc.h @@ -15,41 +15,188 @@ #include <linux/types.h> #include <linux/hdreg.h> #include <linux/version.h> -#endif #include <asm/dasd.h> +#endif + +#define DASD_API_VERSION 0 #define LINE_LENGTH 80 #define VTOC_START_CC 0x0 #define VTOC_START_HH 0x1 +#define FIRST_USABLE_CYL 1 +#define FIRST_USABLE_TRK 2 + +#define DASD_3380_TYPE 13148 +#define DASD_3390_TYPE 13200 +#define DASD_9345_TYPE 37701 + +#define DASD_3380_VALUE 0xbb60 +#define DASD_3390_VALUE 0xe5a2 +#define DASD_9345_VALUE 0xbc98 + +#define VOLSER_LENGTH 6 +#define BIG_DISK_SIZE 0x10000 + +#define VTOC_ERROR "VTOC error:" enum failure {unable_to_open, unable_to_seek, unable_to_write, unable_to_read}; -typedef struct ttr { +unsigned char ASCtoEBC[256] = +{ + /*00 NL SH SX EX ET NQ AK BL */ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + /*08 BS HT LF VT FF CR SO SI */ + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /*10 DL D1 D2 D3 D4 NK SN EB */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26, + /*18 CN EM SB EC FS GS RS US */ + 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, + /*20 SP ! " # $ % & ' */ + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + /*28 ( ) * + , - . / */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + /*30 0 1 2 3 4 5 6 7 */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /*38 8 9 : ; < = > ? */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + /*40 @ A B C D E F G */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /*48 H I J K L M N O */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + /*50 P Q R S T U V W */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + /*58 X Y Z [ \ ] ^ _ */ + 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, + /*60 ` a b c d e f g */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + /*68 h i j k l m n o */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*70 p q r s t u v w */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + /*78 x y z { | } ~ DL */ + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF +}; + + +unsigned char EBCtoASC[256] = +{ + /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC + -ENP ->LF */ + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB + -IUS */ + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC + -INP */ + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL + -SW */ + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + /* 0x40 SP RSP ä ---- */ + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + /* 0x48 . < ( + | */ + 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + /* 0x50 & ---- */ + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + /* 0x58 ß ! $ * ) ; */ + 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, + /* 0x60 - / ---- Ä ---- ---- ---- */ + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + /* 0x68 ---- , % _ > ? */ + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x78 * ` : # @ ' = " */ + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + /* 0x80 * a b c d e f g */ + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + /* 0x88 h i ---- ---- ---- */ + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + /* 0x90 ° j k l m n o p */ + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + /* 0x98 q r ---- ---- */ + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + /* 0xA0 ~ s t u v w x */ + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + /* 0xA8 y z ---- ---- ---- ---- */ + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + /* 0xB0 ^ ---- § ---- */ + 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + /* 0xB8 ---- [ ] ---- ---- ---- ---- */ + 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, + /* 0xC0 { A B C D E F G */ + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + /* 0xC8 H I ---- ö ---- */ + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + /* 0xD0 } J K L M N O P */ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + /* 0xD8 Q R ---- ü */ + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + /* 0xE0 \ S T U V W X */ + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + /* 0xE8 Y Z ---- Ö ---- ---- ---- */ + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + /* 0xF0 0 1 2 3 4 5 6 7 */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 +}; + +typedef struct ttr +{ __u16 tt; __u8 r; } __attribute__ ((packed)) ttr_t; -typedef struct cchhb { +typedef struct cchhb +{ __u16 cc; __u16 hh; __u8 b; } __attribute__ ((packed)) cchhb_t; -typedef struct cchh { +typedef struct cchh +{ __u16 cc; __u16 hh; } __attribute__ ((packed)) cchh_t; -typedef struct labeldate { +typedef struct labeldate +{ __u8 year; __u16 day; } __attribute__ ((packed)) labeldate_t; -typedef struct volume_label { +typedef struct volume_label +{ char volkey[4]; /* volume key = volume label */ char vollbl[4]; /* volume label */ char volid[6]; /* volume identifier */ @@ -66,7 +213,8 @@ typedef struct volume_label { } __attribute__ ((packed)) volume_label_t; -typedef struct extent { +typedef struct extent +{ __u8 typeind; /* extent type indicator */ __u8 seqno; /* extent sequence number */ cchh_t llimit; /* starting point of this extent */ @@ -74,7 +222,8 @@ typedef struct extent { } __attribute__ ((packed)) extent_t; -typedef struct dev_const { +typedef struct dev_const +{ __u16 DS4DSCYL; /* number of logical cyls */ __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ __u16 DS4DEVTK; /* device track length */ @@ -88,7 +237,8 @@ typedef struct dev_const { } __attribute__ ((packed)) dev_const_t; -typedef struct format1_label { +typedef struct format1_label +{ char DS1DSNAM[44]; /* data set name */ __u8 DS1FMTID; /* format identifier */ char DS1DSSN[6]; /* data set serial number */ @@ -124,7 +274,8 @@ typedef struct format1_label { } __attribute__ ((packed)) format1_label_t; -typedef struct format4_label { +typedef struct format4_label +{ char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ __u8 DS4IDFMT; /* format identifier */ cchhb_t DS4HPCHR; /* highest address of a format 1 DSCB */ @@ -153,6 +304,43 @@ typedef struct format4_label { } __attribute__ ((packed)) format4_label_t; +typedef struct ds5ext +{ + __u16 t; /* RTA of the first track of free extent */ + __u16 fc; /* number of whole cylinders in free ext. */ + __u8 ft; /* number of remaining free tracks */ +} __attribute__ ((packed)) ds5ext_t; + + +typedef struct format5_label +{ + char DS5KEYID[4]; /* key identifier */ + ds5ext_t DS5AVEXT; /* first available (free-space) extent. */ + ds5ext_t DS5EXTAV[7]; /* seven available extents */ + __u8 DS5FMTID; /* format identifier */ + ds5ext_t DS5MAVET[18]; /* eighteen available extents */ + cchhb_t DS5PTRDS[5]; /* pointer to next format5 DSCB */ +} __attribute__ ((packed)) format5_label_t; + + +typedef struct ds7ext +{ + __u32 a; /* starting RTA value */ + __u32 b; /* ending RTA value + 1 */ +} __attribute__ ((packed)) ds7ext_t; + + +typedef struct format7_label +{ + char DS7KEYID[4]; /* key identifier */ + ds7ext_t DS7EXTNT[5]; /* space for 5 extent descriptions */ + __u8 DS7FMTID; /* format identifier */ + ds7ext_t DS7ADEXT[11]; /* space for 11 extent descriptions */ + char res1[2]; /* reserved */ + cchhb_t DS7PTRDS; /* pointer to next FMT7 DSCB */ +} __attribute__ ((packed)) format7_label_t; + + char * vtoc_ebcdic_enc ( unsigned char source[LINE_LENGTH], unsigned char target[LINE_LENGTH], @@ -181,45 +369,126 @@ void vtoc_set_date ( __u8 year, __u16 day); +void vtoc_volume_label_init ( + volume_label_t *vlabel); int vtoc_read_volume_label ( char * device, unsigned long vlabel_start, volume_label_t * vlabel); + int vtoc_write_volume_label ( - char * device, + char *device, unsigned long vlabel_start, - volume_label_t * vlabel); + volume_label_t *vlabel); + +void vtoc_volume_label_set_volser ( + volume_label_t *vlabel, + char *volser); + +char *vtoc_volume_label_get_volser ( + volume_label_t *vlabel, + char *volser); + +void vtoc_volume_label_set_key ( + volume_label_t *vlabel, + char *key); + +void vtoc_volume_label_set_label ( + volume_label_t *vlabel, + char *lbl); + +char *vtoc_volume_label_get_label ( + volume_label_t *vlabel, + char *lbl); + void vtoc_read_label ( char *device, unsigned long position, + format1_label_t *f1, format4_label_t *f4, - format1_label_t *f1); + format5_label_t *f5, + format7_label_t *f7); + void vtoc_write_label ( char *device, unsigned long position, + format1_label_t *f1, format4_label_t *f4, - format1_label_t *f1); -void vtoc_init_format4_label ( - struct hd_geometry *geo, - format4_label_t *f4lbl, - unsigned int usable_partitions, - unsigned int cylinders, - unsigned int tracks, - unsigned int blocks); + format5_label_t *f5, + format7_label_t *f7); + + void vtoc_init_format1_label ( char *volid, unsigned int blksize, extent_t *part_extent, format1_label_t *f1); -void vtoc_update_format4_label ( - format4_label_t *f4, - cchhb_t *highest_f1, - __u8 unused_update, - __u16 freespace_update); +void vtoc_init_format4_label ( + format4_label_t *f4lbl, + unsigned int usable_partitions, + unsigned int cylinders, + unsigned int tracks, + unsigned int blocks, + unsigned int blksize, + __u16 dev_type); +void vtoc_update_format4_label ( + format4_label_t *f4, + cchhb_t *highest_f1, + __u16 unused_update); + + +void vtoc_init_format5_label ( + format5_label_t *f5); + +void vtoc_update_format5_label_add ( + format5_label_t *f5, + int verbose, + int cyl, + int trk, + __u16 a, + __u16 b, + __u8 c); + +void vtoc_update_format5_label_del ( + format5_label_t *f5, + int verbose, + int cyl, + int trk, + __u16 a, + __u16 b, + __u8 c); + + +void vtoc_init_format7_label ( + format7_label_t *f7); + +void vtoc_update_format7_label_add ( + format7_label_t *f7, + int verbose, + __u32 a, + __u32 b); + +void vtoc_update_format7_label_del ( + format7_label_t *f7, + int verbose, + __u32 a, + __u32 b); + + +void vtoc_set_freespace( + format4_label_t *f4, + format5_label_t *f5, + format7_label_t *f7, + char ch, + int verbose, + __u32 start, + __u32 stop, + int cyl, + int trk); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2b2c0bb1e7cb..4ac152dcf660 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -180,7 +180,7 @@ extern int * max_segments[MAX_BLKDEV]; #define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK) /* read-ahead in pages.. */ -#define MAX_READAHEAD 127 +#define MAX_READAHEAD 31 #define MIN_READAHEAD 3 #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queue) diff --git a/include/linux/fs.h b/include/linux/fs.h index a716192ba716..a2d4abe3daf6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1316,7 +1316,7 @@ static inline void bforget(struct buffer_head *buf) } extern void set_blocksize(kdev_t, int); extern struct buffer_head * bread(kdev_t, int, int); -extern void wakeup_bdflush(int wait); +extern void wakeup_bdflush(void); extern int brw_page(int, struct page *, kdev_t, int [], int); @@ -1342,7 +1342,7 @@ extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *); extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t); - +extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin); extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *); extern struct file_operations generic_ro_fops; diff --git a/include/linux/ibmtr.h b/include/linux/ibmtr.h index 094d40af864d..dd8cbdc9f1a8 100644 --- a/include/linux/ibmtr.h +++ b/include/linux/ibmtr.h @@ -169,7 +169,7 @@ typedef enum { CLOSED, OPEN } open_state; struct tok_info { unsigned char irq; - __u32 mmio; + void *mmio; unsigned char hw_address[32]; unsigned char adapter_type; unsigned char data_rate; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index b209d49792f6..fcd93ba5e88b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -437,7 +437,15 @@ #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 +#define PCI_DEVICE_ID_SI_635 0x0635 +#define PCI_DEVICE_ID_SI_640 0x0640 +#define PCI_DEVICE_ID_SI_645 0x0645 +#define PCI_DEVICE_ID_SI_650 0x0650 #define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_735 0x0735 +#define PCI_DEVICE_ID_SI_740 0x0740 +#define PCI_DEVICE_ID_SI_745 0x0745 +#define PCI_DEVICE_ID_SI_750 0x0750 #define PCI_DEVICE_ID_SI_630_VGA 0x6300 #define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_900 0x0900 diff --git a/include/linux/serial.h b/include/linux/serial.h index d03c78ba43fc..28da97697470 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -141,7 +141,8 @@ struct serial_uart_config { --- no longer used */ #define ASYNC_CONS_FLOW 0x00800000 /* flow control for console */ -#define ASYNC_INTERNAL_FLAGS 0xFF800000 /* Internal flags */ +#define ASYNC_BOOT_ONLYMCA 0x00400000 /* Probe only if MCA bus */ +#define ASYNC_INTERNAL_FLAGS 0xFFC00000 /* Internal flags */ /* * Multiport serial configuration structure --- external structure diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0537365a817f..421635abc069 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -9,6 +9,11 @@ * Wirzenius wrote this portably, Torvalds fucked it up :-) */ +/* + * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> + * - changed to provide snprintf and vsnprintf functions + */ + #include <stdarg.h> #include <linux/types.h> #include <linux/string.h> @@ -121,14 +126,15 @@ static int skip_atoi(const char **s) #define SPECIAL 32 /* 0x */ #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ -static char * number(char * str, long long num, int base, int size, int precision, int type) +static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type) { char c,sign,tmp[66]; - const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + const char *digits; + const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int i; - if (type & LARGE) - digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + digits = (type & LARGE) ? large_digits : small_digits; if (type & LEFT) type &= ~ZEROPAD; if (base < 2 || base > 36) @@ -162,46 +168,73 @@ static char * number(char * str, long long num, int base, int size, int precisio if (i > precision) precision = i; size -= precision; - if (!(type&(ZEROPAD+LEFT))) - while(size-->0) - *str++ = ' '; - if (sign) - *str++ = sign; + if (!(type&(ZEROPAD+LEFT))) { + while(size-->0) { + if (buf <= end) + *buf = ' '; + ++buf; + } + } + if (sign) { + if (buf <= end) + *buf = sign; + ++buf; + } if (type & SPECIAL) { - if (base==8) - *str++ = '0'; - else if (base==16) { - *str++ = '0'; - *str++ = digits[33]; + if (base==8) { + if (buf <= end) + *buf = '0'; + ++buf; + } else if (base==16) { + if (buf <= end) + *buf = '0'; + ++buf; + if (buf <= end) + *buf = digits[33]; + ++buf; } } - if (!(type & LEFT)) - while (size-- > 0) - *str++ = c; - while (i < precision--) - *str++ = '0'; - while (i-- > 0) - *str++ = tmp[i]; - while (size-- > 0) - *str++ = ' '; - return str; + if (!(type & LEFT)) { + while (size-- > 0) { + if (buf <= end) + *buf = c; + ++buf; + } + } + while (i < precision--) { + if (buf <= end) + *buf = '0'; + ++buf; + } + while (i-- > 0) { + if (buf <= end) + *buf = tmp[i]; + ++buf; + } + while (size-- > 0) { + if (buf <= end) + *buf = ' '; + ++buf; + } + return buf; } /** - * vsprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @fmt: The format string to use - * @args: Arguments for the format string - * - * Call this function if you are already dealing with a va_list. - * You probably want sprintf instead. +* vsnprintf - Format a string and place it in a buffer +* @buf: The buffer to place the result into +* @size: The size of the buffer, including the trailing null space +* @fmt: The format string to use +* @args: Arguments for the format string +* +* Call this function if you are already dealing with a va_list. +* You probably want snprintf instead. */ -int vsprintf(char *buf, const char *fmt, va_list args) +int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { int len; unsigned long long num; int i, base; - char * str; + char *str, *end, c; const char *s; int flags; /* flags to number() */ @@ -210,16 +243,25 @@ int vsprintf(char *buf, const char *fmt, va_list args) int precision; /* min. # of digits for integers; max number of chars for from string */ int qualifier; /* 'h', 'l', or 'L' for integer fields */ - /* 'z' support added 23/7/1999 S.H. */ + /* 'z' support added 23/7/1999 S.H. */ /* 'z' changed to 'Z' --davidm 1/25/99 */ - - for (str=buf ; *fmt ; ++fmt) { + str = buf; + end = buf + size - 1; + + if (end < buf - 1) { + end = ((void *) -1); + size = end - buf + 1; + } + + for (; *fmt ; ++fmt) { if (*fmt != '%') { - *str++ = *fmt; + if (str <= end) + *str = *fmt; + ++str; continue; } - + /* process flags */ flags = 0; repeat: @@ -230,8 +272,8 @@ int vsprintf(char *buf, const char *fmt, va_list args) case ' ': flags |= SPACE; goto repeat; case '#': flags |= SPECIAL; goto repeat; case '0': flags |= ZEROPAD; goto repeat; - } - + } + /* get field width */ field_width = -1; if (isdigit(*fmt)) @@ -272,83 +314,112 @@ int vsprintf(char *buf, const char *fmt, va_list args) base = 10; switch (*fmt) { - case 'c': - if (!(flags & LEFT)) - while (--field_width > 0) - *str++ = ' '; - *str++ = (unsigned char) va_arg(args, int); - while (--field_width > 0) - *str++ = ' '; - continue; - - case 's': - s = va_arg(args, char *); - if (!s) - s = "<NULL>"; - - len = strnlen(s, precision); - - if (!(flags & LEFT)) - while (len < field_width--) - *str++ = ' '; - for (i = 0; i < len; ++i) - *str++ = *s++; - while (len < field_width--) - *str++ = ' '; - continue; - - case 'p': - if (field_width == -1) { - field_width = 2*sizeof(void *); - flags |= ZEROPAD; - } - str = number(str, - (unsigned long) va_arg(args, void *), 16, - field_width, precision, flags); - continue; + case 'c': + if (!(flags & LEFT)) { + while (--field_width > 0) { + if (str <= end) + *str = ' '; + ++str; + } + } + c = (unsigned char) va_arg(args, int); + if (str <= end) + *str = c; + ++str; + while (--field_width > 0) { + if (str <= end) + *str = ' '; + ++str; + } + continue; + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; - case 'n': - if (qualifier == 'l') { - long * ip = va_arg(args, long *); - *ip = (str - buf); - } else if (qualifier == 'Z') { - size_t * ip = va_arg(args, size_t *); - *ip = (str - buf); - } else { - int * ip = va_arg(args, int *); - *ip = (str - buf); - } - continue; + len = strnlen(s, precision); - case '%': - *str++ = '%'; - continue; + if (!(flags & LEFT)) { + while (len < field_width--) { + if (str <= end) + *str = ' '; + ++str; + } + } + for (i = 0; i < len; ++i) { + if (str <= end) + *str = *s; + ++str; ++s; + } + while (len < field_width--) { + if (str <= end) + *str = ' '; + ++str; + } + continue; - /* integer number formats - set up the flags and "break" */ - case 'o': - base = 8; - break; - - case 'X': - flags |= LARGE; - case 'x': - base = 16; - break; - - case 'd': - case 'i': - flags |= SIGN; - case 'u': - break; - - default: - *str++ = '%'; - if (*fmt) - *str++ = *fmt; - else - --fmt; - continue; + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, end, + (unsigned long) va_arg(args, void *), + 16, field_width, precision, flags); + continue; + + + case 'n': + /* FIXME: + * What does C99 say about the overflow case here? */ + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else if (qualifier == 'Z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + if (str <= end) + *str = '%'; + ++str; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (str <= end) + *str = '%'; + ++str; + if (*fmt) { + if (str <= end) + *str = *fmt; + ++str; + } else { + --fmt; + } + continue; } if (qualifier == 'L') num = va_arg(args, long long); @@ -367,13 +438,54 @@ int vsprintf(char *buf, const char *fmt, va_list args) if (flags & SIGN) num = (signed int) num; } - str = number(str, num, base, field_width, precision, flags); + str = number(str, end, num, base, + field_width, precision, flags); } - *str = '\0'; + if (str <= end) + *str = '\0'; + else if (size > 0) + /* don't write out a null byte if the buf size is zero */ + *end = '\0'; + /* the trailing null byte doesn't count towards the total + * ++str; + */ return str-buf; } /** + * snprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @size: The size of the buffer, including the trailing null space + * @fmt: The format string to use + * @...: Arguments for the format string + */ +int snprintf(char * buf, size_t size, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsnprintf(buf,size,fmt,args); + va_end(args); + return i; +} + +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf instead. + */ +int vsprintf(char *buf, const char *fmt, va_list args) +{ + return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args); +} + + +/** * sprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @fmt: The format string to use @@ -389,3 +501,4 @@ int sprintf(char * buf, const char *fmt, ...) va_end(args); return i; } + diff --git a/mm/highmem.c b/mm/highmem.c index 70bc76731aeb..5f3cef59c05f 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -309,7 +309,7 @@ repeat_alloc: * No luck. First, kick the VM so it doesnt idle around while * we are using up our emergency rations. */ - wakeup_bdflush(0); + wakeup_bdflush(); /* * Try to allocate from the emergency pool. @@ -347,7 +347,7 @@ repeat_alloc: * No luck. First, kick the VM so it doesnt idle around while * we are using up our emergency rations. */ - wakeup_bdflush(0); + wakeup_bdflush(); /* * Try to allocate from the emergency pool. diff --git a/mm/shmem.c b/mm/shmem.c index 3bfe6e6b7045..5eb87a6d5df7 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -754,18 +754,8 @@ static int shmem_statfs(struct super_block *sb, struct statfs *buf) buf->f_type = TMPFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; spin_lock (&sb->u.shmem_sb.stat_lock); - if (sb->u.shmem_sb.max_blocks == ULONG_MAX) { - /* - * This is only a guestimate and not honoured. - * We need it to make some programs happy which like to - * test the free space of a file system. - */ - buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages); - buf->f_blocks = buf->f_bfree + ULONG_MAX - sb->u.shmem_sb.free_blocks; - } else { - buf->f_blocks = sb->u.shmem_sb.max_blocks; - buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks; - } + buf->f_blocks = sb->u.shmem_sb.max_blocks; + buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks; buf->f_files = sb->u.shmem_sb.max_inodes; buf->f_ffree = sb->u.shmem_sb.free_inodes; spin_unlock (&sb->u.shmem_sb.stat_lock); @@ -1013,17 +1003,11 @@ static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, return 0; } -static int shmem_remount_fs (struct super_block *sb, int *flags, char *data) +static int shmem_set_size(struct shmem_sb_info *info, + unsigned long max_blocks, unsigned long max_inodes) { int error; - unsigned long max_blocks, blocks; - unsigned long max_inodes, inodes; - struct shmem_sb_info *info = &sb->u.shmem_sb; - - max_blocks = info->max_blocks; - max_inodes = info->max_inodes; - if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) - return -EINVAL; + unsigned long blocks, inodes; spin_lock(&info->stat_lock); blocks = info->max_blocks - info->free_blocks; @@ -1043,6 +1027,17 @@ out: return error; } +static int shmem_remount_fs (struct super_block *sb, int *flags, char *data) +{ + struct shmem_sb_info *info = &sb->u.shmem_sb; + unsigned long max_blocks = info->max_blocks; + unsigned long max_inodes = info->max_inodes; + + if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) + return -EINVAL; + return shmem_set_size(info, max_blocks, max_inodes); +} + int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync) { return 0; @@ -1053,9 +1048,16 @@ static struct super_block *shmem_read_super(struct super_block * sb, void * data { struct inode * inode; struct dentry * root; - unsigned long blocks = ULONG_MAX; /* unlimited */ - unsigned long inodes = ULONG_MAX; /* unlimited */ + unsigned long blocks, inodes; int mode = S_IRWXUGO | S_ISVTX; + struct sysinfo si; + + /* + * Per default we only allow half of the physical ram per + * tmpfs instance + */ + si_meminfo(&si); + blocks = inodes = si.totalram / 2; #ifdef CONFIG_TMPFS if (shmem_parse_options (data, &mode, &blocks, &inodes)) { @@ -1180,6 +1182,10 @@ static int __init init_shmem_fs(void) return PTR_ERR(res); } + /* The internal instance should not do size checking */ + if ((error = shmem_set_size(&res->mnt_sb->u.shmem_sb, ULONG_MAX, ULONG_MAX))) + printk (KERN_ERR "could not set limits on internal tmpfs\n"); + return 0; } diff --git a/mm/vmscan.c b/mm/vmscan.c index 22f8effef852..6bb196e1dc02 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -641,7 +641,7 @@ page_active: /* We only do a few "out of order" flushes. */ maxlaunder = MAX_LAUNDER; /* Kflushd takes care of the rest. */ - wakeup_bdflush(0); + wakeup_bdflush(); goto dirty_page_rescan; } diff --git a/net/atm/common.c b/net/atm/common.c index 37386ca2690f..4e19203beadf 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -210,7 +210,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY && vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC && - vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits)) + vci != ATM_VCI_ANY && vci > dev->ci_range.vci_bits)) return -EINVAL; if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 8749dfb0d76b..569344e9258e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -274,7 +274,7 @@ static int rtnetlink_done(struct netlink_callback *cb) /* Process one rtnetlink message. */ -extern __inline__ int +static __inline__ int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) { struct rtnetlink_link *link; diff --git a/scripts/Menuconfig b/scripts/Menuconfig index b48d36bcb974..8fb747899740 100644 --- a/scripts/Menuconfig +++ b/scripts/Menuconfig @@ -1335,7 +1335,7 @@ set_geometry () { then echo -e "\n\007Your display is too small to run Menuconfig!" echo "It must be at least 19 lines by 80 columns." - exit 0 + exit 1 fi ROWS=$((ROWS-4)) COLS=$((COLS-5)) |
