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
--- /dev/null
+
+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>
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)
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)
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
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.
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
PS: If you have a new working entry, mail it to me.
--
-Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Gerd Knorr <kraxel@bytesex.org>
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
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 8
-EXTRAVERSION =-pre4
+EXTRAVERSION =-pre5
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
$(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 $@ $<
$(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:
*
*/
-#define __ASSEMBLY__
#include <linux/config.h>
#include <asm/segment.h>
#include <linux/version.h>
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;
}
}
}
+ if (!num_processors)
+ printk(KERN_ERR "SMP mptable: no processors registered!\n");
return num_processors;
}
* 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
#define DAC960_DriverVersion "2.4.10"
-#define DAC960_DriverDate "1 February 2001"
+#define DAC960_DriverDate "23 July 2001"
#include <linux/version.h>
#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>
#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>
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);
}
*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++)
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;
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);
DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
DAC960_QueueCommand(Command);
DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
- wait_for_completion(wait);
+ wait_for_completion(Completion);
}
}
return true;
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
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);
}
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;
}
}
}
}
if (CommandType == DAC960_ImmediateCommand)
{
- complete(Command->Waiting);
- Command->Waiting = NULL;
+ complete(Command->Completion);
+ Command->Completion = NULL;
return;
}
if (CommandType == DAC960_QueuedCommand)
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);
}
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;
}
}
}
}
if (CommandType == DAC960_ImmediateCommand)
{
- complete(Command->Waiting);
- Command->Waiting = NULL;
+ complete(Command->Completion);
+ Command->Completion = NULL;
return;
}
if (CommandType == DAC960_QueuedCommand)
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;
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;
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;
}
/* 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
* 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 */
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;
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));
}
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;
}
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);
#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 );
__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";
/*
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 */
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);
}
#include <asm/ptrace.h>
-extern void wakeup_bdflush(int);
extern void reset_vc(unsigned int);
extern struct list_head super_blocks;
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");
{ "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, },
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;
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:
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;
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:
}
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);
break;
}
- packet->state = complete;
+ packet->state = completed;
up(&packet->state_change);
run_task_queue(&packet->complete_tq);
}
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);
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);
/* 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. */
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
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
--- /dev/null
+/*
+ ***************************************************************************
+ *
+ * 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 );
+
#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>
#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>
#define BT878_DEVCTRL 0x40
#define BT878_EN_TBFX 0x02
+#define BT878_EN_VSFX 0x04
#endif
#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>
#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 };
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 }
};
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,
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,
},{
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> */
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,
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,
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,
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!
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));
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 */
{ 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)
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;
}
}
}
+/* 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)
{
}
}
+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 */
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");
{
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;
}
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;
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");
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;
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;
{
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;
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
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;
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)))
}
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:
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);
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);
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;
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);
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;
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);
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;
#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
/* 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_ */
#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>
};
#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)
#include <linux/unistd.h>
#include "audiochip.h"
+#include "msp3400.h"
/* Addresses to scan */
static unsigned short normal_i2c[] = {I2C_CLIENT_END};
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;
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;
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);
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);
}
}
}
}
+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 {
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);
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);
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;
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);
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)
}
if (msp->active)
msp->restart = 1;
-#endif
break;
case AUDC_SET_RADIO:
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... */
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;
}
--- /dev/null
+#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 */
* 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)
*
* 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>
int addr;
int input;
int volume;
- int tone;
+ int bass, treble;
int lf, lr, rf, rr;
int loud;
struct i2c_client c;
/* 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.
*
#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
#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
*/
#define TDA7432_ATTEN_0DB 0x00
+#define TDA7432_MUTE 0x1 << 5
/* Subaddress 0x07 - Loudness Control */
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;
}
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 */
{
struct tda7432 *t = client->data;
d2printk("tda7432: In tda7432_command\n");
-#if 0
- __u16 *sarg = arg;
-#endif
switch (cmd) {
/* --- v4l ioctls --- */
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:
* 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 */
}
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 */
&driver
};
-#ifdef MODULE
-int init_module(void)
-#else
int tda7432_init(void)
-#endif
{
if ( (loudness < 0) || (loudness > 15) )
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:
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
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))
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) {
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) {
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;
#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
#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 */
int inputreg;
int inputmap[8];
int inputmute;
+ int inputmask;
};
static struct CHIPDESC chiplist[];
/* current settings */
__u16 left,right,treble,bass,mode;
-
+ int prevmode;
/* thread */
struct task_struct *thread;
struct semaphore *notify;
/* ---------------------------------------------------------------------- */
-/* i2c addresses */
+/* i2c addresses */
static unsigned short normal_i2c[] = {
I2C_TDA8425 >> 1,
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;
continue;
/* have a look what's going on */
- dprintk("%s: thread checkmode\n", chip->c.name);
desc->checkmode(chip);
/* schedule next check */
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);
}
#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;
* 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
* 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)
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;
}
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)
setmode: tda9840_setmode,
checkmode: generic_checkmode,
- init: { 2, { TDA9840_SW, 0x2a } }
+ init: { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+ /* ,TDA9840_SW, TDA9840_MONO */} }
},
{
name: "tda9873h",
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
},
{
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;
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);
{
struct CHIPSTATE *chip = client->data;
+ del_timer(&chip->wt);
if (NULL != chip->thread) {
/* shutdown async thread */
DECLARE_MUTEX_LOCKED(sem);
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 --- */
}
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 */
}
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);
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;
#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>
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);
#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>
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;
*
*/
-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;
}
}
-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 */
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;
}
}
-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;
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);
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);
/*
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);
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);
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);
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);
}
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);
" 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);
}
lp->stats.rx_dropped++;
}
}
- wait_for_completion(dev, RxDiscard);
+ tc574_wait_for_completion(dev, RxDiscard);
}
return worklimit;
/*
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);
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);
}
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);
" 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);
}
}
}
/* 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);
#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>
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;
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)
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;
{
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;
#ifndef MODULE
#ifndef PCMCIA
dev = init_trdev(dev, 0);
+ if (!dev)
+ return -ENOMEM;
#endif
#endif
* 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);
/*
* 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 */
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: ");
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
ti->turbo=1;
t_irq=turbo_irq[i];
}
-#endif
+#endif /* !PCMCIA */
ti->readlog_pending = 0;
init_waitqueue_head(&ti->wait_for_reset);
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;
}
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");
default:
DPRINTK("Unknown shared ram paging info %01X\n",
ti->shared_ram_paging);
+ iounmap(t_mmio);
kfree(ti);
return -ENODEV;
break;
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 */
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",
* 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");
}
/*
{ 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 },
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
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
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)
+
-/*
+/*
* 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
* 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>
#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>
#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"
" 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
/* 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
*/
return r;
}
-/*
+/*
* function: dasd_destroy_devreg
* destroys the dasd_devreg_t given as argument
*/
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
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
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
{
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)
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;
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
{
char *tmp = str;
int count = 0;
- do {
+ while (tmp != NULL && *tmp != '\0') {
char *end;
int len;
end = strchr (tmp, ',');
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
}
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
{
char *temp;
int from, to;
+ int features = 0;
if (*str) {
/* turn off probeonly mode, if any dasd parameter is present */
} 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++;
}
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 *
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)
{
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 */
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;
}
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) {
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
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);
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 **
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];
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 */
}
/*
- * 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)
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);
dasd_profile_add_counter (endtime, dasd_io_time3, device);
}
-/* SECTION: (de)queueing of requests to channel program queues */
-/*
- * 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
+/* 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
*/
-static inline void
-dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+ccw_req_t *
+dasd_alloc_request (char *magic, int cplength, int datasize, dasd_device_t* device)
{
- if (q->head != NULL) {
- q->tail->next = cqr;
- } else
- q->head = cqr;
- cqr->next = NULL;
+ 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
+ * appends the cqr given as argument to the queue
+ * has to be called with the queue lock (namely the s390_irq_lock) acquired
+ */
+inline void
+dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+{
+ if (q->head != NULL) {
+ q->tail->next = cqr;
+ } else
+ q->head = cqr;
+ cqr->next = NULL;
q->tail = 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;
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
*/
int rc = 0;
dasd_device_t *device = cqr->device;
int irq;
- unsigned long long now;
+ unsigned long long now;
if (!cqr) {
BUG ();
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
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
return;
}
-/*
+/*
* function dasd_get_queue
* returns the queue corresponding to a device behind a kdev
*/
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
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
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;
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.
* 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
*/
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();
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);
}
* 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 == NULL)
- return NULL;
+ 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;
+ }
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;
}
* 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
* 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
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)
{
_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;
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;
}
- default:{
-
- dasd_ioctl_list_t *old = dasd_find_ioctl(no);
- if ( old ) {
- rc = old->handler(inp,no,data);
+ 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 {
- DASD_MESSAGE (KERN_INFO, device,
- "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),
- data);
- rc = -EINVAL;
- }
+ 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) {
+ 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",
+ 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),
+ data);
+ rc = -ENOTTY;
+ }
break;
}
}
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;
}
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;
}
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 */
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;
}
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;
}
}
}
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');
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)
{
- device->request_queue.plugged = 1; /* inhibit further calls of request_fn */
+ atomic_set(&device->plugged,0);
+ dasd_schedule_bh(device);
}
static void
-dasd_unplug_device (dasd_device_t *device)
+dasd_flush_chanq ( dasd_device_t * device, int destroy )
{
- generic_unplug_device(&device->request_queue);
+ 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 )
+{
+ 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_disable_ranges (dasd_range_t *range,
+ dasd_discipline_t *d,
+ int all, int force )
+{
+ 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)
{
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;
}
"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);
- }
+ dasd_disable_volume(device, 0);
}
-static int
-dasd_enable_single_volume (int irq)
+int
+dasd_oper_handler (int irq, devreg_t * devreg)
{
+ int devno;
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);
+ major_info_t *major_info = NULL;
+ dasd_range_t *rptr,range;
+ dasd_device_t *device = NULL;
+ struct list_head *l;
+ int i;
+
+ devno = get_devno_by_irq (irq);
+ if (devno == -ENODEV) {
+ rc = -ENODEV;
+ goto out;
}
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
+ /* 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)
+ break;
+ }
+ 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 */
-int
-dasd_oper_handler (int irq, devreg_t * devreg)
+static inline dasd_device_t **
+dasd_find_device_addr ( int devno )
{
- 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;
+ 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) {
+ int rc;
+
+ if ((rc = dasd_register_major (NULL)) <= 0) {
+
+ DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr,
+ "%s",
+ "out of major numbers!");
+ break;
+ }
+ }
+ 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));
+ *addr = device;
+ device->lowmem_ccws = (void*)get_free_page (GFP_ATOMIC|GFP_DMA);
+ if (device->lowmem_ccws == NULL) {
+ rc = -ENOMEM;
+ goto noccw;
+ }
+#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;
}
- if (dasd_autodetect) {
- dasd_add_range (devno, 0);
+#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);
+ break;
+ }
+ }
+ if (i < DASD_PER_MAJOR) /* we found one */
+ break;
}
- rc = dasd_enable_single_volume (irq);
- return rc;
+ 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;
+ 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 ) ;
}
-#endif /* CONFIG_DASD_DYNAMIC */
-/*
- * function dasd_set_device_level
+/*
+ * function dasd_set_device_level
*/
static int
-dasd_set_device_level (unsigned int irq, int desired_level,
- dasd_discipline_t * discipline, int flags)
+dasd_set_device_level (unsigned int devno,
+ dasd_discipline_t * discipline,
+ int to_state)
{
int rc = 0;
- int devno;
- dasd_device_t **device_addr, *device;
- int current_level;
- major_info_t *major_info = NULL;
- struct list_head *l;
- int i, minor, major;
- ccw_req_t *cqr = NULL;
- struct gendisk *dd;
+ dasd_device_t **device_addr;
+ dasd_device_t *device;
+ int from_state;
- 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)
- return -ENODEV;
- }
- }
- if (dasd_devindex_from_devno (devno) < 0) {
- return -ENODEV;
- }
- 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;
- }
- }
- 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;
- }
- memset (device, 0, sizeof (dasd_device_t));
- *device_addr = device;
- }
- list_for_each(l,&dasd_major_info[0].list) {
- int i;
- 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);
- break;
- }
- }
- if (i < DASD_PER_MAJOR)
- 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 {
- 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)
+ 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 */
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;
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;
}
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;
}
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
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;
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,
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;
}
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");
}
init_module (void)
{
int rc = 0;
- return dasd_init ();
+ rc = dasd_init ();
return rc;
}
* 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
*/
#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)"
* 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;
/* 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;
}
--- /dev/null
+/*
+ * 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 */
* 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"
* SECTION DEBUG ROUTINES
*****************************************************************************
*/
-#ifdef ERP_DEBUG
void
log_erp_chain (ccw_req_t *cqr,
int caller,
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;
}
/* 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 */
-
/*
*****************************************************************************
* 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 */
/*
* 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
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;
*****************************************************************************
*/
+/*
+ * 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
*
/* 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 */
void
dasd_3990_erp_restart_queue (unsigned long erp)
{
+
ccw_req_t *cqr = (void *) erp;
dasd_device_t *device = cqr->device;
unsigned long flags;
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,
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
*
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
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,
} 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,
} /* end dasd_3990_erp_alternate_path */
-#ifdef ERP_FULL_ERP
/*
* DASD_3990_ERP_DCTL
*
* 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
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;
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;
return dctl_cqr;
} /* end dasd_3990_erp_DCTL */
-#endif /* ERP_FULL_ERP */
/*
* DASD_3990_ERP_ACTION_1
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);
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");
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);
*****************************************************************************
*/
-#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
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 */
* 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 */
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 */
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;
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
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;
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 "
} 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");
} 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
*
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
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
*
* 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
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);
} /* end dasd_3990_erp_env_data */
-#ifdef ERP_FULL_ERP
/*
* DASD_3990_ERP_NO_REC
*
* 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 */
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
* 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)) {
(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)) {
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)) {
(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;
}
*****************************************************************************
*/
-#ifdef ERP_FULL_ERP
/*
* DASD_3990_ERPACTION_10_32
*
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
* 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
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;
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;
}
/* 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;
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 */
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) {
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;
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;
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;
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;
}
/* 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;
}
/* Imprecise ending is not set -> addr from IRB-SCSW */
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");
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) {
} /* 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
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 */
/*
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,
dasd_3990_erp_compound_code (ccw_req_t *erp,
char *sense)
{
-
if (sense[25] & DASD_SENSE_BIT_2) {
break;
default:
- BUG();
+ /* should not happen - continue */
+
}
}
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");
}
* 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
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);
return erp;
} /* end dasd_3990_erp_compound */
-#endif /* ERP_FULL_ERP */
/*
* DASD_3990_ERP_INSPECT_32
dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
char *sense )
{
+
dasd_device_t *device = erp->device;
erp->function = dasd_3990_erp_inspect_32;
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 */
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 */
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 */
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");
sense);
break;
- default: /* all others errors */
- DASD_MESSAGE (KERN_WARNING, device,
- "%s",
- "default ERP taken");
+ default: /* all others errors - default 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 ! */
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;
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);
}
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,
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
* 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 */
/*
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) ||
} 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);
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);
* 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 */
/*
* 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;
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);
}
/* 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);
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
#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 *);
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 */
*/
#include <asm/ccwcache.h>
-#include <asm/dasd.h>
+#include "dasd_int.h"
+#include "dasd_9336_erp.h"
#ifdef PRINTK_HEADER
#undef PRINTK_HEADER
* 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;
--- /dev/null
+/*
+ * 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 */
*/
#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;
}
#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 */
* fixed partition handling and HDIO_GETGEO
*/
+#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <asm/debug.h>
#include <asm/irq.h>
#include <asm/s390dyn.h>
+#include "dasd_int.h"
#include "dasd_diag.h"
#ifdef PRINTK_HEADER
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;
".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;
}
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"
".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
rc = dia250 (iib, INIT_BIO);
- return rc&3;
+ return rc & 3;
}
static __inline__ int
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
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;
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;
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
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;
}
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
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;
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
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)
{
}
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;
}
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)
{
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
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
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;
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;
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;
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);
/*
* 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
#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)
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)
}
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;
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) {
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;
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) {
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;
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;
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
{
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;
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;
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)
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;
}
{
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;
}
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;
}
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);
}
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;
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;
}
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:
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)
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;
/* 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;
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)
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 */
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");
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");
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",
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,
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,
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
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
#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
#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];
__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;
__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;
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;
__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 {
__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 */
#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
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)
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)
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;
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
device->sizes.s2b_shift++;
device->sizes.blocks = (private->rdc_data.blk_bdsa);
- device->sizes.pt_block = 1;
+ device->sizes.pt_block = 1;
return rc;
}
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:
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;
}
{
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;
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) {
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;
}
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)
{
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)
{
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;
}
{
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
#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 */
__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;
__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 {
__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 */
--- /dev/null
+/*
+ * 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:
+ */
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
struct Scsi_Host *shpnt = aha152x_host[i];
if (shpnt && HOSTDATA(shpnt)->service) {
HOSTDATA(shpnt)->service=0;
- complete(shpnt);
+ is_complete(shpnt);
}
}
}
* bottom-half handler
*
*/
-static void complete(struct Scsi_Host *shpnt)
+static void is_complete(struct Scsi_Host *shpnt)
{
int dataphase;
unsigned long flags;
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),
* 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>
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
{
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];
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;
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) {
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);
/* 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;
}
for (k = 0; k < 16; k++) {
dev->id[k].curr_req = 0;
+ dev->sp[k] = 0x04;
}
}
h = 0;
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;
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;
tmport = base_io + 0x51;
outb(0x20, tmport);
+ tscam(h);
is880(h, base_io);
tmport = base_io + 0x38;
outb(0xb0, tmport);
{
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);
{
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;
}
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;
static Scsi_Host_Template driver_template = ATP870U;
#include "scsi_module.c"
-
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
Send questions/comments to:
-donald.zimmerman@compaq.com
-dszimmerman@yahoo.com
+Amy Vanzant-Hodge (fibrechannel@compaq.com)
+
// 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);
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, \
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 */
#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
#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"
#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
// 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
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
// 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
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)).
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,
// 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++;
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
else // we know what FC device to operate on...
{
+ // printk("ioctl CMND %d", Cmnd);
switch (Cmnd)
{
// Passthrough provides a mechanism to bypass the RAID
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
// 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],
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);
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;
}
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;
}
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;
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
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
}
-
-
-#ifdef MODULE
-
static Scsi_Host_Template driver_template = CPQFCTS;
#include "scsi_module.c"
-
-#endif
-
-
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).
#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
CPQFCHBA* cpqfcHBAdata,
TachFCHDR_GCMND* fchs);
-
// (see scsi_error.c comments on kernel task creation)
void cpqfcTSWorkerThread( void *host)
pFcPort->flogi = FALSE;
pFcPort->LOGO_timer = 0;
pFcPort->device_blocked = TRUE; // block Scsi Requests
+ pFcPort->ScsiNexus.VolumeSetAddressing=0;
}
ULONG ulStatus;
UCHAR *ucBuff;
-
if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
{
printk("Discard Q'd ReportLun command\n");
Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
Cmnd->target = pLoggedInPort->ScsiNexus.target;
-
+
ulStatus = cpqfcTSBuildExchange(
cpqfcHBAdata,
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
{
break;
-
case BLS_ABTS: // FC defined basic link service command ABTS
// Abort Sequence
// Fibre Channel SCSI 'originator' sequences...
// (originator means 'initiator' in FCP-SCSI)
+
case SCSI_IWE: // TachLite Initiator Write Entry
{
PFC_LOGGEDIN_PORT pLoggedInPort =
// 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)
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.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>
#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>
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...) /* */
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);
/* /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,*/
//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;
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;
}
}
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 |
SCSI_RESET_IRQ_EI );
nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
- nsp_setup_fifo(base, FALSE);
+ nsp_setup_fifo(data, FALSE);
return TRUE;
}
/*
* 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;
//DEBUG(0, __FUNCTION__ "()in\n");
-
phase = nsp_index_read(base, SCSIBUSMON);
if(phase != BUSMON_BUS_FREE) {
//DEBUG(0, " bus busy\n");
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;
}
/*
* 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;
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];
*/
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);
/*
* 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);
}
/*
* 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);
}
/* 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>");
/*
* 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");
}
count = nsp_fifo_count(SCpnt);
- if (nsp_data.FifoCount == count) {
+ if (data->FifoCount == count) {
//DEBUG(0, " not use bypass quirk\n");
return 0;
}
* 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;
/*
* 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;
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);
/*
* 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);
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);
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);
/*
* 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;
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);
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);
/*
* 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);
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 |
return 0;
}
+#include "nsp_message.c"
/*
* interrupt handler
*/
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);
/*
/*
* 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;
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);
}
/*
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;
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;
}
}
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);
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;
/* 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);
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;
}
tmpSC->SCp.phase = PH_COMMAND;
- nsp_nexus(tmpSC);
+ nsp_nexus(tmpSC, data);
/* write scsi command */
nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
tmpSC->SCp.phase = PH_DATA;
tmpSC->SCp.have_data_in = IO_OUT;
- nsp_pio_write(tmpSC);
+ nsp_pio_write(tmpSC, data);
break;
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;
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:
return;
timer_out:
- nsp_start_timer(tmpSC, 1000/102);
+ nsp_start_timer(tmpSC, data, 1000/102);
return;
}
#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)
{
}
/*======================================================================
- 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.
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;
/* 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 */
}
}
link->irq.Handler = &nspintr;
+ link->irq.Instance = &nsp_data;
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
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 */
/*======================================================================
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;
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;
*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.
======================================================================*/
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;
Scsi_Device *dev;
dev_node_t **tail, *node;
struct Scsi_Host *host;
+ nsp_hw_data *data = &nsp_data;
DEBUG(0, __FUNCTION__ "() in\n");
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;
}
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;
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK) {
- nsp_detach(link);
+ nsp_cs_detach(link);
}
-} /* nsp_release */
+} /* nsp_cs_release */
/*======================================================================
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)
{
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:
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:
}
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;
"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);
/*
*
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__
/* 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)
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
} 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
/*
};
-#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__*/
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
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 */
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.
*/
--- /dev/null
+/*==========================================================================
+ 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 */
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)) {
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);
*/
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;
/*
- * $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
*
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;
} 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;
spin_unlock(&lru_list_lock);
write_locked_buffers(array, count);
- goto repeat;
+ return -EAGAIN;
}
unlock_buffer(bh);
put_bh(bh);
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)
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();
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)
loop = 1;
goto cleaned_buffers_try_again;
}
- wakeup_bdflush(0);
+ wakeup_bdflush();
}
return 0;
}
* 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);
}
/*
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)
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}
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);
}
NULL
};
+/*
+ * 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;
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}..
* 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>
#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,
[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 )
{
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) {
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) {
add_gd_partition( hd, MINOR(dev), 0, 0);
add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
}
-
+
printk ( "\n" );
bforget(bh);
return 1;
}
-
#include <asm/uaccess.h>
struct file_operations generic_ro_fops = {
+ llseek: generic_file_llseek,
read: generic_file_read,
mmap: generic_file_mmap,
};
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;
#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
#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
#define __ARCH_S390_CACHE_H
#define L1_CACHE_BYTES 256
-#define L1_CACHE_SHIFT 16
+#define L1_CACHE_SHIFT 8
#endif
* 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
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 */
/*
#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 */
} __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 */
} __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 */
} __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 */
} __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 */
} __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],
__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);
#define __ARCH_S390_CACHE_H
#define L1_CACHE_BYTES 256
-#define L1_CACHE_SHIFT 16
+#define L1_CACHE_SHIFT 8
#endif
* 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
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 */
/*
#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 */
} __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 */
} __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 */
} __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 */
} __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 */
} __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],
__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);
#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)
}
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);
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;
struct tok_info {
unsigned char irq;
- __u32 mmio;
+ void *mmio;
unsigned char hw_address[32];
unsigned char adapter_type;
unsigned char data_rate;
#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
--- 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
* 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>
#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)
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() */
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:
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))
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);
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
va_end(args);
return i;
}
+
* 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.
* 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.
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);
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;
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;
{
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)) {
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;
}
/* 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;
}
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;
/* 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;
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))