diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /drivers/block | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'drivers/block')
59 files changed, 10185 insertions, 4842 deletions
diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 6fba7d5fc..7c00c4dd2 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -11,6 +11,11 @@ fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY fi +if [ "$CONFIG_MAC" = "y" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP + fi +fi tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE comment 'Please see Documentation/ide.txt for help/info on IDE drives' @@ -43,7 +48,6 @@ else bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS - bool ' Generic ATA-66 support (DANGEROUS)' CONFIG_IDEDMA_ULTRA_66 define_bool IDEDMA_PCI_EXPERIMENTAL y else define_bool IDEDMA_PCI_EXPERIMENTAL n @@ -52,7 +56,9 @@ else bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + if [ "$CONFIG_X86" = "y" ]; then + bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + fi bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 fi @@ -61,10 +67,13 @@ else "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA fi - bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX - if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_PIIX" = "y" ]; then - bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 + if [ "$CONFIG_X86" = "y" ]; then + bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PIIX" = "y" ]; then + bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + fi fi if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 @@ -80,9 +89,14 @@ else bool ' Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE fi fi + if [ "$CONFIG_X86" = "y" ]; then + bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 + fi if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + if [ "$CONFIG_X86" = "y" ]; then + bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + fi fi fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then @@ -206,9 +220,11 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ + "$CONFIG_BLK_DEV_HPT366" = "y" -o \ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ + "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y else diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c new file mode 100644 index 000000000..06eed2279 --- /dev/null +++ b/drivers/block/DAC960.c @@ -0,0 +1,3570 @@ +/* + + Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers + + Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com> + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + + The author respectfully requests that any modifications to this software be + sent directly to him for evaluation and testing. + +*/ + + +#define DAC960_DriverVersion "2.2.4" +#define DAC960_DriverDate "23 August 1999" + + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/blk.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/hdreg.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/locks.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <linux/proc_fs.h> +#include <linux/reboot.h> +#include <linux/timer.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/segment.h> +#include <linux/spinlock.h> +#include <asm/uaccess.h> +#include "DAC960.h" + + +/* + DAC960_ControllerCount is the number of DAC960 Controllers detected. +*/ + +static int + DAC960_ControllerCount = 0; + + +/* + DAC960_ActiveControllerCount is the number of Active DAC960 Controllers + detected. +*/ + +static int + DAC960_ActiveControllerCount = 0; + + +/* + DAC960_Controllers is an array of pointers to the DAC960 Controller + structures. +*/ + +static DAC960_Controller_T + *DAC960_Controllers[DAC960_MaxControllers] = { NULL }; + + +/* + DAC960_FileOperations is the File Operations structure for DAC960 Logical + Disk Devices. +*/ + +static FileOperations_T + DAC960_FileOperations = + { llseek: NULL, + read: block_read, + write: block_write, + readdir: NULL, + poll: NULL, + ioctl: DAC960_IOCTL, + mmap: NULL, + open: DAC960_Open, + release: DAC960_Release, + fsync: block_fsync, + fasync: NULL, + check_media_change: NULL, + revalidate: NULL }; + + +/* + DAC960_ProcDirectoryEntry is the DAC960 /proc/rd directory entry. +*/ + +static PROC_DirectoryEntry_T + DAC960_ProcDirectoryEntry; + + +/* + DAC960_NotifierBlock is the Notifier Block structure for DAC960 Driver. +*/ + +static NotifierBlock_T + DAC960_NotifierBlock = { DAC960_Finalize, NULL, 0 }; + + +/* + DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name, + Copyright Notice, and Electronic Mail Address. +*/ + +static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller) +{ + DAC960_Announce("***** DAC960 RAID Driver Version " + DAC960_DriverVersion " of " + DAC960_DriverDate " *****\n", Controller); + DAC960_Announce("Copyright 1998-1999 by Leonard N. Zubkoff " + "<lnz@dandelion.com>\n", Controller); +} + + +/* + DAC960_Failure prints a standardized error message, and then returns false. +*/ + +static boolean DAC960_Failure(DAC960_Controller_T *Controller, + char *ErrorMessage) +{ + DAC960_Error("While configuring DAC960 PCI RAID Controller at\n", + Controller); + if (Controller->IO_Address == 0) + DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " + "PCI Address 0x%X\n", Controller, + Controller->Bus, Controller->Device, + Controller->Function, Controller->PCI_Address); + else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " + "0x%X PCI Address 0x%X\n", Controller, + Controller->Bus, Controller->Device, + Controller->Function, Controller->IO_Address, + Controller->PCI_Address); + DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage); + return false; +} + + +/* + DAC960_ClearCommand clears critical fields of Command. +*/ + +static inline void DAC960_ClearCommand(DAC960_Command_T *Command) +{ + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + CommandMailbox->Words[0] = 0; + CommandMailbox->Words[1] = 0; + CommandMailbox->Words[2] = 0; + CommandMailbox->Words[3] = 0; + Command->CommandStatus = 0; +} + + +/* + DAC960_AllocateCommand allocates a Command structure from Controller's + free list. +*/ + +static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T + *Controller) +{ + DAC960_Command_T *Command = Controller->FreeCommands; + if (Command == NULL) return NULL; + Controller->FreeCommands = Command->Next; + Command->Next = NULL; + return Command; +} + + +/* + DAC960_DeallocateCommand deallocates Command, returning it to Controller's + free list. +*/ + +static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + Command->Next = Controller->FreeCommands; + Controller->FreeCommands = Command; +} + + +/* + DAC960_QueueCommand queues Command. +*/ + +static void DAC960_QueueCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_CommandMailbox_T *NextCommandMailbox; + CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands; + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + NextCommandMailbox = Controller->NextCommandMailbox; + DAC960_V5_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); + if (Controller->PreviousCommandMailbox1->Words[0] == 0 || + Controller->PreviousCommandMailbox2->Words[0] == 0) + { + if (Controller->DualModeMemoryMailboxInterface) + DAC960_V5_MemoryMailboxNewCommand(ControllerBaseAddress); + else DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress); + } + Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1; + Controller->PreviousCommandMailbox1 = NextCommandMailbox; + if (++NextCommandMailbox > Controller->LastCommandMailbox) + NextCommandMailbox = Controller->FirstCommandMailbox; + Controller->NextCommandMailbox = NextCommandMailbox; + break; + case DAC960_V4_Controller: + NextCommandMailbox = Controller->NextCommandMailbox; + DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); + if (Controller->PreviousCommandMailbox1->Words[0] == 0 || + Controller->PreviousCommandMailbox2->Words[0] == 0) + { + if (Controller->DualModeMemoryMailboxInterface) + DAC960_V4_MemoryMailboxNewCommand(ControllerBaseAddress); + else DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress); + } + Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1; + Controller->PreviousCommandMailbox1 = NextCommandMailbox; + if (++NextCommandMailbox > Controller->LastCommandMailbox) + NextCommandMailbox = Controller->FirstCommandMailbox; + Controller->NextCommandMailbox = NextCommandMailbox; + break; + case DAC960_V3_Controller: + while (DAC960_V3_MailboxFullP(ControllerBaseAddress)) + udelay(1); + DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox); + DAC960_V3_NewCommand(ControllerBaseAddress); + break; + } +} + + +/* + DAC960_ExecuteCommand executes Command and waits for completion. It + returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + Semaphore_T Semaphore = MUTEX_LOCKED; + unsigned long ProcessorFlags; + Command->Semaphore = &Semaphore; + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (!in_interrupt()) + down(&Semaphore); + return Command->CommandStatus == DAC960_NormalCompletion; +} + + +/* + DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for + completion. It returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller, + DAC960_CommandOpcode_T CommandOpcode, + void *DataPointer) +{ + DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + boolean Result; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3.CommandOpcode = CommandOpcode; + CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer); + Result = DAC960_ExecuteCommand(Command); + DAC960_DeallocateCommand(Command); + return Result; +} + + +/* + DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for + completion. It returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller, + DAC960_CommandOpcode_T CommandOpcode, + unsigned char Channel, + unsigned char TargetID, + void *DataPointer) +{ + DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + boolean Result; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3D.CommandOpcode = CommandOpcode; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer); + Result = DAC960_ExecuteCommand(Command); + DAC960_DeallocateCommand(Command); + return Result; +} + + +/* + DAC960_EnableMemoryMailboxInterface enables the Memory Mailbox Interface. +*/ + +static boolean DAC960_EnableMemoryMailboxInterface(DAC960_Controller_T + *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_CommandMailbox_T *CommandMailboxesMemory; + DAC960_StatusMailbox_T *StatusMailboxesMemory; + DAC960_CommandMailbox_T CommandMailbox; + DAC960_CommandStatus_T CommandStatus; + void *SavedMemoryMailboxesAddress = NULL; + short NextCommandMailboxIndex = 0; + short NextStatusMailboxIndex = 0; + int TimeoutCounter = 1000000, i; + if (Controller->ControllerType == DAC960_V5_Controller) + DAC960_V5_RestoreMemoryMailboxInfo(Controller, + &SavedMemoryMailboxesAddress, + &NextCommandMailboxIndex, + &NextStatusMailboxIndex); + else DAC960_V4_RestoreMemoryMailboxInfo(Controller, + &SavedMemoryMailboxesAddress, + &NextCommandMailboxIndex, + &NextStatusMailboxIndex); + if (SavedMemoryMailboxesAddress == NULL) + CommandMailboxesMemory = + (DAC960_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1); + else CommandMailboxesMemory = SavedMemoryMailboxesAddress; + memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1); + Controller->FirstCommandMailbox = CommandMailboxesMemory; + CommandMailboxesMemory += DAC960_CommandMailboxCount - 1; + Controller->LastCommandMailbox = CommandMailboxesMemory; + Controller->NextCommandMailbox = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + if (--NextCommandMailboxIndex < 0) + NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1; + Controller->PreviousCommandMailbox1 = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + if (--NextCommandMailboxIndex < 0) + NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1; + Controller->PreviousCommandMailbox2 = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + StatusMailboxesMemory = + (DAC960_StatusMailbox_T *) (CommandMailboxesMemory + 1); + Controller->FirstStatusMailbox = StatusMailboxesMemory; + StatusMailboxesMemory += DAC960_StatusMailboxCount - 1; + Controller->LastStatusMailbox = StatusMailboxesMemory; + Controller->NextStatusMailbox = + &Controller->FirstStatusMailbox[NextStatusMailboxIndex]; + if (SavedMemoryMailboxesAddress != NULL) return true; + /* Enable the Memory Mailbox Interface. */ + Controller->DualModeMemoryMailboxInterface = true; + CommandMailbox.TypeX.CommandOpcode = 0x2B; + CommandMailbox.TypeX.CommandIdentifier = 0; + CommandMailbox.TypeX.CommandOpcode2 = 0x14; + CommandMailbox.TypeX.CommandMailboxesBusAddress = + Virtual_to_Bus(Controller->FirstCommandMailbox); + CommandMailbox.TypeX.StatusMailboxesBusAddress = + Virtual_to_Bus(Controller->FirstStatusMailbox); + for (i = 0; i < 2; i++) + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + while (--TimeoutCounter >= 0) + { + if (DAC960_V5_HardwareMailboxEmptyP(ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + DAC960_V5_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress); + while (--TimeoutCounter >= 0) + { + if (DAC960_V5_HardwareMailboxStatusAvailableP( + ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + CommandStatus = DAC960_V5_ReadStatusRegister(ControllerBaseAddress); + DAC960_V5_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); + DAC960_V5_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); + if (CommandStatus == DAC960_NormalCompletion) return true; + Controller->DualModeMemoryMailboxInterface = false; + CommandMailbox.TypeX.CommandOpcode2 = 0x10; + break; + case DAC960_V4_Controller: + while (--TimeoutCounter >= 0) + { + if (!DAC960_V4_HardwareMailboxFullP(ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + DAC960_V4_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress); + while (--TimeoutCounter >= 0) + { + if (DAC960_V4_HardwareMailboxStatusAvailableP( + ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress); + DAC960_V4_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); + DAC960_V4_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); + if (CommandStatus == DAC960_NormalCompletion) return true; + Controller->DualModeMemoryMailboxInterface = false; + CommandMailbox.TypeX.CommandOpcode2 = 0x10; + break; + default: + break; + } + return false; +} + + +/* + DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating + the PCI Configuration Space for Controller Type. +*/ + +static void DAC960_DetectControllers(DAC960_ControllerType_T ControllerType) +{ + unsigned short VendorID = 0, DeviceID = 0; + unsigned int MemoryWindowSize = 0; + PCI_Device_T *PCI_Device = NULL; + switch (ControllerType) + { + case DAC960_V5_Controller: + VendorID = PCI_VENDOR_ID_DEC; + DeviceID = PCI_DEVICE_ID_DEC_21285; + MemoryWindowSize = DAC960_V5_RegisterWindowSize; + break; + case DAC960_V4_Controller: + VendorID = PCI_VENDOR_ID_MYLEX; + DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V4; + MemoryWindowSize = DAC960_V4_RegisterWindowSize; + break; + case DAC960_V3_Controller: + VendorID = PCI_VENDOR_ID_MYLEX; + DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V3; + MemoryWindowSize = DAC960_V3_RegisterWindowSize; + break; + } + while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL) + { + DAC960_Controller_T *Controller = (DAC960_Controller_T *) + kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC); + DAC960_IO_Address_T IO_Address = 0; + DAC960_PCI_Address_T PCI_Address = 0; + unsigned char Bus = PCI_Device->bus->number; + unsigned char DeviceFunction = PCI_Device->devfn; + unsigned char Device = DeviceFunction >> 3; + unsigned char Function = DeviceFunction & 0x7; + unsigned int IRQ_Channel = PCI_Device->irq; + unsigned long BaseAddress0 = PCI_Device->base_address[0]; + unsigned long BaseAddress1 = PCI_Device->base_address[1]; + unsigned short SubsystemVendorID, SubsystemDeviceID; + int CommandIdentifier; + pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID, + &SubsystemVendorID); + pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID, + &SubsystemDeviceID); + switch (ControllerType) + { + case DAC960_V5_Controller: + if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX && + SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960P_V5)) + goto Ignore; + PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK; + break; + case DAC960_V4_Controller: + PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK; + break; + case DAC960_V3_Controller: + IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK; + PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK; + break; + } + if (DAC960_ControllerCount == DAC960_MaxControllers) + { + DAC960_Error("More than %d DAC960 Controllers detected - " + "ignoring from Controller at\n", + NULL, DAC960_MaxControllers); + goto Ignore; + } + if (Controller == NULL) + { + DAC960_Error("Unable to allocate Controller structure for " + "Controller at\n", NULL); + goto Ignore; + } + memset(Controller, 0, sizeof(DAC960_Controller_T)); + init_waitqueue_head(&Controller->CommandWaitQueue); + Controller->ControllerNumber = DAC960_ControllerCount; + DAC960_Controllers[DAC960_ControllerCount++] = Controller; + DAC960_AnnounceDriver(Controller); + Controller->ControllerType = ControllerType; + Controller->IO_Address = IO_Address; + Controller->PCI_Address = PCI_Address; + Controller->Bus = Bus; + Controller->Device = Device; + Controller->Function = Function; + sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); + /* + Acquire shared access to the IRQ Channel. + */ + if (IRQ_Channel == 0) + { + DAC960_Error("IRQ Channel %d illegal for Controller at\n", + Controller, IRQ_Channel); + goto Failure; + } + strcpy(Controller->FullModelName, "DAC960"); + if (request_irq(IRQ_Channel, DAC960_InterruptHandler, + SA_SHIRQ, Controller->FullModelName, Controller) < 0) + { + DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n", + Controller, IRQ_Channel); + goto Failure; + } + Controller->IRQ_Channel = IRQ_Channel; + /* + Map the Controller Register Window. + */ + if (MemoryWindowSize < PAGE_SIZE) + MemoryWindowSize = PAGE_SIZE; + Controller->MemoryMappedAddress = + ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize); + Controller->BaseAddress = + Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK); + if (Controller->MemoryMappedAddress == NULL) + { + DAC960_Error("Unable to map Controller Register Window for " + "Controller at\n", Controller); + goto Failure; + } + switch (ControllerType) + { + case DAC960_V5_Controller: + DAC960_V5_DisableInterrupts(Controller->BaseAddress); + if (!DAC960_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to Enable Memory Mailbox Interface " + "for Controller at\n", Controller); + goto Failure; + } + DAC960_V5_EnableInterrupts(Controller->BaseAddress); + break; + case DAC960_V4_Controller: + DAC960_V4_DisableInterrupts(Controller->BaseAddress); + if (!DAC960_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to Enable Memory Mailbox Interface " + "for Controller at\n", Controller); + goto Failure; + } + DAC960_V4_EnableInterrupts(Controller->BaseAddress); + break; + case DAC960_V3_Controller: + request_region(Controller->IO_Address, 0x80, + Controller->FullModelName); + DAC960_V3_EnableInterrupts(Controller->BaseAddress); + break; + } + DAC960_ActiveControllerCount++; + for (CommandIdentifier = 0; + CommandIdentifier < DAC960_MaxChannels; + CommandIdentifier++) + { + Controller->Commands[CommandIdentifier].Controller = Controller; + Controller->Commands[CommandIdentifier].Next = + Controller->FreeCommands; + Controller->FreeCommands = &Controller->Commands[CommandIdentifier]; + } + continue; + Failure: + if (IO_Address == 0) + DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " + "PCI Address 0x%X\n", Controller, + Bus, Device, Function, PCI_Address); + else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " + "0x%X PCI Address 0x%X\n", Controller, + Bus, Device, Function, IO_Address, PCI_Address); + if (Controller == NULL) break; + if (Controller->IRQ_Channel > 0) + free_irq(IRQ_Channel, Controller); + if (Controller->MemoryMappedAddress != NULL) + iounmap(Controller->MemoryMappedAddress); + DAC960_Controllers[Controller->ControllerNumber] = NULL; + Ignore: + kfree(Controller); + } +} + + +/* + DAC960_ReadControllerConfiguration reads the Configuration Information + from Controller and initializes the Controller structure. +*/ + +static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T + *Controller) +{ + DAC960_Enquiry2_T Enquiry2; + DAC960_Config2_T Config2; + int LogicalDriveNumber, Channel, TargetID; + if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry, + &Controller->Enquiry[0])) + return DAC960_Failure(Controller, "ENQUIRY"); + if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2)) + return DAC960_Failure(Controller, "ENQUIRY2"); + if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2)) + return DAC960_Failure(Controller, "READ CONFIG2"); + if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation, + &Controller->LogicalDriveInformation[0])) + return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION"); + for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState, + Channel, TargetID, + &Controller->DeviceState[0][Channel][TargetID])) + return DAC960_Failure(Controller, "GET DEVICE STATE"); + /* + Initialize the Controller Model Name and Full Model Name fields. + */ + switch (Enquiry2.HardwareID.SubModel) + { + case DAC960_P_PD_PU: + if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra) + strcpy(Controller->ModelName, "DAC960PU"); + else strcpy(Controller->ModelName, "DAC960PD"); + break; + case DAC960_PL: + strcpy(Controller->ModelName, "DAC960PL"); + break; + case DAC960_PG: + strcpy(Controller->ModelName, "DAC960PG"); + break; + case DAC960_PJ: + strcpy(Controller->ModelName, "DAC960PJ"); + break; + case DAC960_PR: + strcpy(Controller->ModelName, "DAC960PR"); + break; + case DAC960_PT: + strcpy(Controller->ModelName, "DAC960PT"); + break; + case DAC960_PTL0: + strcpy(Controller->ModelName, "DAC960PTL0"); + break; + case DAC960_PRL: + strcpy(Controller->ModelName, "DAC960PRL"); + break; + case DAC960_PTL1: + strcpy(Controller->ModelName, "DAC960PTL1"); + break; + case DAC1164_P: + strcpy(Controller->ModelName, "DAC1164P"); + break; + default: + return DAC960_Failure(Controller, "MODEL VERIFICATION"); + } + strcpy(Controller->FullModelName, "Mylex "); + strcat(Controller->FullModelName, Controller->ModelName); + /* + Initialize the Controller Firmware Version field and verify that it + is a supported firmware version. The supported firmware versions are: + + DAC1164P 5.06 and above + DAC960PTL/PRL/PJ/PG 4.06 and above + DAC960PU/PD/PL 3.51 and above + */ + sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d", + Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion, + Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID); + if (!((Controller->FirmwareVersion[0] == '5' && + strcmp(Controller->FirmwareVersion, "5.06") >= 0) || + (Controller->FirmwareVersion[0] == '4' && + strcmp(Controller->FirmwareVersion, "4.06") >= 0) || + (Controller->FirmwareVersion[0] == '3' && + strcmp(Controller->FirmwareVersion, "3.51") >= 0))) + { + DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION"); + DAC960_Error("Firmware Version = '%s'\n", Controller, + Controller->FirmwareVersion); + return false; + } + /* + Initialize the Controller Channels, Memory Size, and SAF-TE Enclosure + Management Enabled fields. + */ + Controller->Channels = Enquiry2.ActualChannels; + Controller->MemorySize = Enquiry2.MemorySize >> 20; + Controller->SAFTE_EnclosureManagementEnabled = + Enquiry2.FaultManagementType == DAC960_SAFTE; + /* + Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive + Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments. + The Driver Queue Depth must be at most one less than the Controller Queue + Depth to allow for an automatic drive rebuild operation. + */ + Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands; + Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1; + Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives; + Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand; + Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries; + /* + Initialize the Stripe Size, Segment Size, and Geometry Translation. + */ + Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor + >> (10 - DAC960_BlockSizeBits); + Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor + >> (10 - DAC960_BlockSizeBits); + switch (Config2.DriveGeometry) + { + case DAC960_Geometry_128_32: + Controller->GeometryTranslationHeads = 128; + Controller->GeometryTranslationSectors = 32; + break; + case DAC960_Geometry_255_63: + Controller->GeometryTranslationHeads = 255; + Controller->GeometryTranslationSectors = 63; + break; + default: + return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY"); + } + /* + Initialize the Logical Drive Initial State. + */ + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + Controller->LogicalDriveInitialState[LogicalDriveNumber] = + Controller->LogicalDriveInformation[0] + [LogicalDriveNumber].LogicalDriveState; + Controller->LastRebuildStatus = DAC960_NoRebuildOrCheckInProgress; + return true; +} + + +/* + DAC960_ReportControllerConfiguration reports the Configuration Information of + Controller. +*/ + +static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T + *Controller) +{ + DAC960_Info("Configuring Mylex %s PCI RAID Controller\n", + Controller, Controller->ModelName); + DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n", + Controller, Controller->FirmwareVersion, + Controller->Channels, Controller->MemorySize); + DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ", + Controller, Controller->Bus, + Controller->Device, Controller->Function); + if (Controller->IO_Address == 0) + DAC960_Info("Unassigned\n", Controller); + else DAC960_Info("0x%X\n", Controller, Controller->IO_Address); + DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n", + Controller, Controller->PCI_Address, + (unsigned long) Controller->BaseAddress, + Controller->IRQ_Channel); + DAC960_Info(" Controller Queue Depth: %d, " + "Maximum Blocks per Command: %d\n", + Controller, Controller->ControllerQueueDepth, + Controller->MaxBlocksPerCommand); + DAC960_Info(" Driver Queue Depth: %d, " + "Maximum Scatter/Gather Segments: %d\n", + Controller, Controller->DriverQueueDepth, + Controller->MaxScatterGatherSegments); + DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, " + "BIOS Geometry: %d/%d\n", Controller, + Controller->StripeSize, + Controller->SegmentSize, + Controller->GeometryTranslationHeads, + Controller->GeometryTranslationSectors); + if (Controller->SAFTE_EnclosureManagementEnabled) + DAC960_Info(" SAF-TE Enclosure Management Enabled\n", Controller); + return true; +} + + +/* + DAC960_ReadDeviceConfiguration reads the Device Configuration Information by + requesting the SCSI Inquiry and SCSI Inquiry Unit Serial Number information + for each device connected to Controller. +*/ + +static boolean DAC960_ReadDeviceConfiguration(DAC960_Controller_T *Controller) +{ + DAC960_DCDB_T DCDBs[DAC960_MaxChannels], *DCDB; + Semaphore_T Semaphores[DAC960_MaxChannels], *Semaphore; + unsigned long ProcessorFlags; + int Channel, TargetID; + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + for (Channel = 0; Channel < Controller->Channels; Channel++) + { + DAC960_Command_T *Command = &Controller->Commands[Channel]; + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->InquiryStandardData[Channel][TargetID]; + InquiryStandardData->PeripheralDeviceType = 0x1F; + Semaphore = &Semaphores[Channel]; + *Semaphore = MUTEX_LOCKED; + DCDB = &DCDBs[Channel]; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + Command->Semaphore = Semaphore; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB; + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + DCDB->Channel = Channel; + DCDB->TargetID = TargetID; + DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem; + DCDB->EarlyStatus = false; + DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds; + DCDB->NoAutomaticRequestSense = false; + DCDB->DisconnectPermitted = true; + DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData); + DCDB->CDBLength = 6; + DCDB->TransferLengthHigh4 = 0; + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 0; /* EVPD = 0 */ + DCDB->CDB[2] = 0; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + for (Channel = 0; Channel < Controller->Channels; Channel++) + { + DAC960_Command_T *Command = &Controller->Commands[Channel]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + &Controller->InquiryUnitSerialNumber[Channel][TargetID]; + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + Semaphore = &Semaphores[Channel]; + down(Semaphore); + if (Command->CommandStatus != DAC960_NormalCompletion) continue; + Command->Semaphore = Semaphore; + DCDB = &DCDBs[Channel]; + DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber); + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 1; /* EVPD = 1 */ + DCDB->CDB[2] = 0x80; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + down(Semaphore); + } + } + return true; +} + + +/* + DAC960_ReportDeviceConfiguration reports the Device Configuration Information + of Controller. +*/ + +static boolean DAC960_ReportDeviceConfiguration(DAC960_Controller_T *Controller) +{ + int LogicalDriveNumber, Channel, TargetID; + DAC960_Info(" Physical Devices:\n", Controller); + for (Channel = 0; Channel < Controller->Channels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->InquiryStandardData[Channel][TargetID]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + &Controller->InquiryUnitSerialNumber[Channel][TargetID]; + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + DAC960_ErrorTable_T *ErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex]; + DAC960_ErrorTableEntry_T *ErrorEntry = + &ErrorTable->ErrorTableEntries[Channel][TargetID]; + char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)]; + char Model[1+sizeof(InquiryStandardData->ProductIdentification)]; + char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)]; + char SerialNumber[1+sizeof(InquiryUnitSerialNumber + ->ProductSerialNumber)]; + int i; + if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue; + for (i = 0; i < sizeof(Vendor)-1; i++) + { + unsigned char VendorCharacter = + InquiryStandardData->VendorIdentification[i]; + Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~' + ? VendorCharacter : ' '); + } + Vendor[sizeof(Vendor)-1] = '\0'; + for (i = 0; i < sizeof(Model)-1; i++) + { + unsigned char ModelCharacter = + InquiryStandardData->ProductIdentification[i]; + Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~' + ? ModelCharacter : ' '); + } + Model[sizeof(Model)-1] = '\0'; + for (i = 0; i < sizeof(Revision)-1; i++) + { + unsigned char RevisionCharacter = + InquiryStandardData->ProductRevisionLevel[i]; + Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~' + ? RevisionCharacter : ' '); + } + Revision[sizeof(Revision)-1] = '\0'; + DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n", + Controller, Channel, TargetID, (TargetID < 10 ? " " : ""), + Vendor, Model, Revision); + if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F) + { + int SerialNumberLength = InquiryUnitSerialNumber->PageLength; + if (SerialNumberLength > + sizeof(InquiryUnitSerialNumber->ProductSerialNumber)) + SerialNumberLength = + sizeof(InquiryUnitSerialNumber->ProductSerialNumber); + for (i = 0; i < SerialNumberLength; i++) + { + unsigned char SerialNumberCharacter = + InquiryUnitSerialNumber->ProductSerialNumber[i]; + SerialNumber[i] = + (SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~' + ? SerialNumberCharacter : ' '); + } + SerialNumber[SerialNumberLength] = '\0'; + DAC960_Info(" Serial Number: %s\n", + Controller, SerialNumber); + } + if (DeviceState->Present && DeviceState->DeviceType == DAC960_DiskType) + { + if (Controller->DeviceResetCount[Channel][TargetID] > 0) + DAC960_Info(" Disk Status: %s, %d blocks, %d resets\n", + Controller, + (DeviceState->DeviceState == DAC960_Device_Dead + ? "Dead" + : DeviceState->DeviceState == DAC960_Device_WriteOnly + ? "Write-Only" + : DeviceState->DeviceState == DAC960_Device_Online + ? "Online" : "Standby"), + DeviceState->DiskSize, + Controller->DeviceResetCount[Channel][TargetID]); + else + DAC960_Info(" Disk Status: %s, %d blocks\n", Controller, + (DeviceState->DeviceState == DAC960_Device_Dead + ? "Dead" + : DeviceState->DeviceState == DAC960_Device_WriteOnly + ? "Write-Only" + : DeviceState->DeviceState == DAC960_Device_Online + ? "Online" : "Standby"), + DeviceState->DiskSize); + } + if (ErrorEntry->ParityErrorCount > 0 || + ErrorEntry->SoftErrorCount > 0 || + ErrorEntry->HardErrorCount > 0 || + ErrorEntry->MiscErrorCount > 0) + DAC960_Info(" Errors - Parity: %d, Soft: %d, " + "Hard: %d, Misc: %d\n", Controller, + ErrorEntry->ParityErrorCount, + ErrorEntry->SoftErrorCount, + ErrorEntry->HardErrorCount, + ErrorEntry->MiscErrorCount); + } + DAC960_Info(" Logical Drives:\n", Controller); + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + { + DAC960_LogicalDriveInformation_T *LogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex][LogicalDriveNumber]; + DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n", + Controller, Controller->ControllerNumber, LogicalDriveNumber, + LogicalDriveInformation->RAIDLevel, + (LogicalDriveInformation->LogicalDriveState == + DAC960_LogicalDrive_Online + ? "Online" + : LogicalDriveInformation->LogicalDriveState == + DAC960_LogicalDrive_Critical + ? "Critical" : "Offline"), + LogicalDriveInformation->LogicalDriveSize, + (LogicalDriveInformation->WriteBack + ? "Write Back" : "Write Thru")); + } + return true; +} + + +/* + DAC960_RegisterBlockDevice registers the Block Device structures + associated with Controller. +*/ + +static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) +{ + static void (*RequestFunctions[DAC960_MaxControllers])(void) = + { DAC960_RequestFunction0, DAC960_RequestFunction1, + DAC960_RequestFunction2, DAC960_RequestFunction3, + DAC960_RequestFunction4, DAC960_RequestFunction5, + DAC960_RequestFunction6, DAC960_RequestFunction7 }; + int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; + GenericDiskInfo_T *GenericDiskInfo; + int MinorNumber; + /* + Register the Block Device Major Number for this DAC960 Controller. + */ + if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0) + { + DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n", + Controller, MajorNumber); + return false; + } + /* + Initialize the I/O Request Function. + */ + blk_dev[MajorNumber].request_fn = + RequestFunctions[Controller->ControllerNumber]; + /* + Initialize the Disk Partitions array, Partition Sizes array, Block Sizes + array, Max Sectors per Request array, and Max Segments per Request array. + */ + for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++) + { + Controller->BlockSizes[MinorNumber] = BLOCK_SIZE; + Controller->MaxSectorsPerRequest[MinorNumber] = + Controller->MaxBlocksPerCommand; + Controller->MaxSegmentsPerRequest[MinorNumber] = + Controller->MaxScatterGatherSegments; + } + Controller->GenericDiskInfo.part = Controller->DiskPartitions; + Controller->GenericDiskInfo.sizes = Controller->PartitionSizes; + blksize_size[MajorNumber] = Controller->BlockSizes; + max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest; + max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest; + /* + Initialize Read Ahead to 128 sectors. + */ + read_ahead[MajorNumber] = 128; + /* + Complete initialization of the Generic Disk Information structure. + */ + Controller->GenericDiskInfo.major = MajorNumber; + Controller->GenericDiskInfo.major_name = "rd"; + Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits; + Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions; + Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives; + Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo; + Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount; + Controller->GenericDiskInfo.real_devices = Controller; + Controller->GenericDiskInfo.next = NULL; + /* + Install the Generic Disk Information structure at the end of the list. + */ + if ((GenericDiskInfo = gendisk_head) != NULL) + { + while (GenericDiskInfo->next != NULL) + GenericDiskInfo = GenericDiskInfo->next; + GenericDiskInfo->next = &Controller->GenericDiskInfo; + } + else gendisk_head = &Controller->GenericDiskInfo; + /* + Indicate the Block Device Registration completed successfully, + */ + return true; +} + + +/* + DAC960_UnregisterBlockDevice unregisters the Block Device structures + associated with Controller. +*/ + +static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller) +{ + int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; + /* + Unregister the Block Device Major Number for this DAC960 Controller. + */ + unregister_blkdev(MajorNumber, "rd"); + /* + Remove the I/O Request Function. + */ + blk_dev[MajorNumber].request_fn = NULL; + /* + Remove the Disk Partitions array, Partition Sizes array, Block Sizes + array, Max Sectors per Request array, and Max Segments per Request array. + */ + Controller->GenericDiskInfo.part = NULL; + Controller->GenericDiskInfo.sizes = NULL; + blk_size[MajorNumber] = NULL; + blksize_size[MajorNumber] = NULL; + max_sectors[MajorNumber] = NULL; + max_segments[MajorNumber] = NULL; + /* + Remove the Generic Disk Information structure from the list. + */ + if (gendisk_head != &Controller->GenericDiskInfo) + { + GenericDiskInfo_T *GenericDiskInfo = gendisk_head; + while (GenericDiskInfo != NULL && + GenericDiskInfo->next != &Controller->GenericDiskInfo) + GenericDiskInfo = GenericDiskInfo->next; + if (GenericDiskInfo != NULL) + GenericDiskInfo->next = GenericDiskInfo->next->next; + } + else gendisk_head = Controller->GenericDiskInfo.next; +} + + +/* + DAC960_InitializeController initializes Controller. +*/ + +static void DAC960_InitializeController(DAC960_Controller_T *Controller) +{ + if (DAC960_ReadControllerConfiguration(Controller) && + DAC960_ReportControllerConfiguration(Controller) && + DAC960_ReadDeviceConfiguration(Controller) && + DAC960_ReportDeviceConfiguration(Controller) && + DAC960_RegisterBlockDevice(Controller)) + { + /* + Initialize the Command structures. + */ + DAC960_Command_T *Commands = Controller->Commands; + int CommandIdentifier; + Controller->FreeCommands = NULL; + for (CommandIdentifier = 0; + CommandIdentifier < Controller->DriverQueueDepth; + CommandIdentifier++) + { + Commands[CommandIdentifier].Controller = Controller; + Commands[CommandIdentifier].Next = Controller->FreeCommands; + Controller->FreeCommands = &Commands[CommandIdentifier]; + } + /* + Initialize the Monitoring Timer. + */ + init_timer(&Controller->MonitoringTimer); + Controller->MonitoringTimer.expires = + jiffies + DAC960_MonitoringTimerInterval; + Controller->MonitoringTimer.data = (unsigned long) Controller; + Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction; + add_timer(&Controller->MonitoringTimer); + Controller->ControllerInitialized = true; + } + else DAC960_FinalizeController(Controller); +} + + +/* + DAC960_FinalizeController finalizes Controller. +*/ + +static void DAC960_FinalizeController(DAC960_Controller_T *Controller) +{ + if (Controller->ControllerInitialized) + { + del_timer(&Controller->MonitoringTimer); + DAC960_Notice("Flushing Cache...", Controller); + DAC960_ExecuteType3(Controller, DAC960_Flush, NULL); + DAC960_Notice("done\n", Controller); + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + if (!Controller->DualModeMemoryMailboxInterface) + DAC960_V5_SaveMemoryMailboxInfo(Controller); + break; + case DAC960_V4_Controller: + if (!Controller->DualModeMemoryMailboxInterface) + DAC960_V4_SaveMemoryMailboxInfo(Controller); + break; + case DAC960_V3_Controller: + break; + } + } + free_irq(Controller->IRQ_Channel, Controller); + iounmap(Controller->MemoryMappedAddress); + if (Controller->IO_Address > 0) + release_region(Controller->IO_Address, 0x80); + DAC960_UnregisterBlockDevice(Controller); + DAC960_Controllers[Controller->ControllerNumber] = NULL; + kfree(Controller); +} + + +/* + DAC960_Initialize initializes the DAC960 Driver. +*/ + +void DAC960_Initialize(void) +{ + int ControllerNumber; + DAC960_DetectControllers(DAC960_V5_Controller); + DAC960_DetectControllers(DAC960_V4_Controller); + DAC960_DetectControllers(DAC960_V3_Controller); + if (DAC960_ActiveControllerCount == 0) return; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + if (DAC960_Controllers[ControllerNumber] != NULL) + DAC960_InitializeController(DAC960_Controllers[ControllerNumber]); + DAC960_CreateProcEntries(); + register_reboot_notifier(&DAC960_NotifierBlock); +} + + +/* + DAC960_Finalize finalizes the DAC960 Driver. +*/ + +static int DAC960_Finalize(NotifierBlock_T *NotifierBlock, + unsigned long Event, + void *Buffer) +{ + int ControllerNumber; + if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF)) + return NOTIFY_DONE; + if (DAC960_ActiveControllerCount == 0) return NOTIFY_OK; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + if (DAC960_Controllers[ControllerNumber] != NULL) + DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]); + DAC960_DestroyProcEntries(); + unregister_reboot_notifier(&DAC960_NotifierBlock); + return NOTIFY_OK; +} + + +/* + DAC960_ProcessRequest attempts to remove one I/O Request from Controller's + I/O Request Queue and queues it to the Controller. WaitForCommand is true if + this function should wait for a Command to become available if necessary. + This function returns true if an I/O Request was queued and false otherwise. +*/ + +static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller, + boolean WaitForCommand) +{ + IO_Request_T **RequestQueuePointer = + &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request; + IO_Request_T *Request; + DAC960_Command_T *Command; + char *RequestBuffer; + while (true) + { + Request = *RequestQueuePointer; + if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false; + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) break; + if (!WaitForCommand) return false; + spin_unlock(&io_request_lock); + sleep_on(&Controller->CommandWaitQueue); + spin_lock_irq(&io_request_lock); + } + DAC960_ClearCommand(Command); + if (Request->cmd == READ) + Command->CommandType = DAC960_ReadCommand; + else Command->CommandType = DAC960_WriteCommand; + Command->Semaphore = Request->sem; + Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev); + Command->BlockNumber = + Request->sector + + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect; + Command->BlockCount = Request->nr_sectors; + Command->SegmentCount = Request->nr_segments; + Command->BufferHeader = Request->bh; + RequestBuffer = Request->buffer; + Request->rq_status = RQ_INACTIVE; + *RequestQueuePointer = Request->next; + wake_up(&wait_for_request); + if (Command->SegmentCount == 1) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + if (Command->CommandType == DAC960_ReadCommand) + CommandMailbox->Type5.CommandOpcode = DAC960_Read; + else CommandMailbox->Type5.CommandOpcode = DAC960_Write; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer); + } + else + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_ScatterGatherSegment_T + *ScatterGatherList = Command->ScatterGatherList; + BufferHeader_T *BufferHeader = Command->BufferHeader; + char *LastDataEndPointer = NULL; + int SegmentNumber = 0; + if (Command->CommandType == DAC960_ReadCommand) + CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather; + else + CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList); + CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount; + while (BufferHeader != NULL) + { + if (BufferHeader->b_data == LastDataEndPointer) + { + ScatterGatherList[SegmentNumber-1].SegmentByteCount += + BufferHeader->b_size; + LastDataEndPointer += BufferHeader->b_size; + } + else + { + ScatterGatherList[SegmentNumber].SegmentDataPointer = + Virtual_to_Bus(BufferHeader->b_data); + ScatterGatherList[SegmentNumber].SegmentByteCount = + BufferHeader->b_size; + LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size; + if (SegmentNumber++ > Controller->MaxScatterGatherSegments) + panic("DAC960: Scatter/Gather Segment Overflow\n"); + } + BufferHeader = BufferHeader->b_reqnext; + } + if (SegmentNumber != Command->SegmentCount) + panic("DAC960: SegmentNumber != SegmentCount\n"); + } + DAC960_QueueCommand(Command); + return true; +} + + +/* + DAC960_ProcessRequests attempts to remove as many I/O Requests as possible + from Controller's I/O Request Queue and queue them to the Controller. +*/ + +static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller) +{ + int Counter = 0; + while (DAC960_ProcessRequest(Controller, Counter++ == 0)) ; +} + + +/* + DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0. +*/ + +static void DAC960_RequestFunction0(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[0]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1. +*/ + +static void DAC960_RequestFunction1(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[1]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2. +*/ + +static void DAC960_RequestFunction2(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[2]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3. +*/ + +static void DAC960_RequestFunction3(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[3]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4. +*/ + +static void DAC960_RequestFunction4(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[4]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5. +*/ + +static void DAC960_RequestFunction5(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[5]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6. +*/ + +static void DAC960_RequestFunction6(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[6]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7. +*/ + +static void DAC960_RequestFunction7(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[7]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_ReadWriteError prints an appropriate error message for Command when + an error occurs on a Read or Write operation. +*/ + +static void DAC960_ReadWriteError(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + char *CommandName = "UNKNOWN"; + switch (Command->CommandType) + { + case DAC960_ReadCommand: + case DAC960_ReadRetryCommand: + CommandName = "READ"; + break; + case DAC960_WriteCommand: + case DAC960_WriteRetryCommand: + CommandName = "WRITE"; + break; + case DAC960_MonitoringCommand: + case DAC960_ImmediateCommand: + case DAC960_QueuedCommand: + break; + } + switch (Command->CommandStatus) + { + case DAC960_IrrecoverableDataError: + DAC960_Error("Irrecoverable Data Error on %s:\n", + Controller, CommandName); + break; + case DAC960_LogicalDriveNonexistentOrOffline: + DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n", + Controller, CommandName); + break; + case DAC960_AccessBeyondEndOfLogicalDrive: + DAC960_Error("Attempt to Access Beyond End of Logical Drive " + "on %s:\n", Controller, CommandName); + break; + case DAC960_BadDataEncountered: + DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName); + break; + default: + DAC960_Error("Unexpected Error Status %04X on %s:\n", + Controller, Command->CommandStatus, CommandName); + break; + } + DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %d..%d\n", + Controller, Controller->ControllerNumber, + Command->LogicalDriveNumber, Command->BlockNumber, + Command->BlockNumber + Command->BlockCount - 1); + if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0) + DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %d..%d\n", + Controller, Controller->ControllerNumber, + Command->LogicalDriveNumber, + DAC960_PartitionNumber(Command->BufferHeader->b_rdev), + Command->BufferHeader->b_rsector, + Command->BufferHeader->b_rsector + Command->BlockCount - 1); +} + + +/* + DAC960_ProcessCompletedBuffer performs completion processing for an + individual Buffer. +*/ + +static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader, + boolean SuccessfulIO) +{ + BufferHeader->b_end_io(BufferHeader, SuccessfulIO); +} + + +/* + DAC960_ProcessCompletedCommand performs completion processing for Command. +*/ + +static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + DAC960_CommandType_T CommandType = Command->CommandType; + DAC960_CommandOpcode_T CommandOpcode = + Command->CommandMailbox.Common.CommandOpcode; + DAC960_CommandStatus_T CommandStatus = Command->CommandStatus; + BufferHeader_T *BufferHeader = Command->BufferHeader; + if (CommandType == DAC960_ReadCommand || + CommandType == DAC960_WriteCommand) + { + if (CommandStatus == DAC960_NormalCompletion) + { + /* + Perform completion processing for all buffers in this I/O Request. + */ + while (BufferHeader != NULL) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + DAC960_ProcessCompletedBuffer(BufferHeader, true); + BufferHeader = NextBufferHeader; + } + /* + Wake up requestor for swap file paging requests. + */ + if (Command->Semaphore != NULL) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + } + add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber); + } + else if ((CommandStatus == DAC960_IrrecoverableDataError || + CommandStatus == DAC960_BadDataEncountered) && + BufferHeader != NULL && + BufferHeader->b_reqnext != NULL) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + if (CommandType == DAC960_ReadCommand) + { + Command->CommandType = DAC960_ReadRetryCommand; + CommandMailbox->Type5.CommandOpcode = DAC960_Read; + } + else + { + Command->CommandType = DAC960_WriteRetryCommand; + CommandMailbox->Type5.CommandOpcode = DAC960_Write; + } + Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.BusAddress = + Virtual_to_Bus(BufferHeader->b_data); + DAC960_QueueCommand(Command); + return; + } + else + { + if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline) + DAC960_ReadWriteError(Command); + /* + Perform completion processing for all buffers in this I/O Request. + */ + while (BufferHeader != NULL) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + DAC960_ProcessCompletedBuffer(BufferHeader, false); + BufferHeader = NextBufferHeader; + } + /* + Wake up requestor for swap file paging requests. + */ + if (Command->Semaphore != NULL) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + } + } + } + else if (CommandType == DAC960_ReadRetryCommand || + CommandType == DAC960_WriteRetryCommand) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + /* + Perform completion processing for this single buffer. + */ + if (CommandStatus == DAC960_NormalCompletion) + DAC960_ProcessCompletedBuffer(BufferHeader, true); + else + { + if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline) + DAC960_ReadWriteError(Command); + DAC960_ProcessCompletedBuffer(BufferHeader, false); + } + if (NextBufferHeader != NULL) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + Command->BlockNumber += + BufferHeader->b_size >> DAC960_BlockSizeBits; + Command->BlockCount = + NextBufferHeader->b_size >> DAC960_BlockSizeBits; + Command->BufferHeader = NextBufferHeader; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = + Virtual_to_Bus(NextBufferHeader->b_data); + DAC960_QueueCommand(Command); + return; + } + } + else if (CommandType == DAC960_MonitoringCommand || + CommandOpcode == DAC960_Enquiry || + CommandOpcode == DAC960_GetRebuildProgress) + { + if (CommandType != DAC960_MonitoringCommand) + { + if (CommandOpcode == DAC960_Enquiry) + memcpy(&Controller->Enquiry[Controller->EnquiryIndex ^ 1], + Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress), + sizeof(DAC960_Enquiry_T)); + else if (CommandOpcode == DAC960_GetRebuildProgress) + memcpy(&Controller->RebuildProgress, + Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress), + sizeof(DAC960_RebuildProgress_T)); + } + if (CommandOpcode == DAC960_Enquiry) + { + DAC960_Enquiry_T *OldEnquiry = + &Controller->Enquiry[Controller->EnquiryIndex]; + DAC960_Enquiry_T *NewEnquiry = + &Controller->Enquiry[Controller->EnquiryIndex ^= 1]; + unsigned int OldCriticalLogicalDriveCount = + OldEnquiry->CriticalLogicalDriveCount; + unsigned int NewCriticalLogicalDriveCount = + NewEnquiry->CriticalLogicalDriveCount; + if (NewEnquiry->StatusFlags.DeferredWriteError != + OldEnquiry->StatusFlags.DeferredWriteError) + DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller, + (NewEnquiry->StatusFlags.DeferredWriteError + ? "TRUE" : "FALSE")); + if ((NewCriticalLogicalDriveCount > 0 || + NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) || + (NewEnquiry->OfflineLogicalDriveCount > 0 || + NewEnquiry->OfflineLogicalDriveCount != + OldEnquiry->OfflineLogicalDriveCount) || + (NewEnquiry->DeadDriveCount > 0 || + NewEnquiry->DeadDriveCount != + OldEnquiry->DeadDriveCount) || + (NewEnquiry->EventLogSequenceNumber != + OldEnquiry->EventLogSequenceNumber) || + Controller->MonitoringTimerCount == 0 || + (jiffies - Controller->SecondaryMonitoringTime + >= DAC960_SecondaryMonitoringInterval)) + { + Controller->NeedLogicalDriveInformation = true; + Controller->NewEventLogSequenceNumber = + NewEnquiry->EventLogSequenceNumber; + Controller->NeedErrorTableInformation = true; + Controller->NeedDeviceStateInformation = true; + Controller->DeviceStateChannel = 0; + Controller->DeviceStateTargetID = -1; + Controller->SecondaryMonitoringTime = jiffies; + } + if (NewEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress || + NewEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress || + OldEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress || + OldEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress) + Controller->NeedRebuildProgress = true; + if (OldEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress) + switch (NewEnquiry->RebuildFlag) + { + case DAC960_NoStandbyRebuildOrCheckInProgress: + DAC960_Progress("Consistency Check Completed Successfully\n", + Controller); + break; + case DAC960_StandbyRebuildInProgress: + case DAC960_BackgroundRebuildInProgress: + break; + case DAC960_BackgroundCheckInProgress: + Controller->NeedConsistencyCheckProgress = true; + break; + case DAC960_StandbyRebuildCompletedWithError: + DAC960_Progress("Consistency Check Completed with Error\n", + Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_DriveFailed: + DAC960_Progress("Consistency Check Failed - " + "Physical Drive Failed\n", Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed: + DAC960_Progress("Consistency Check Failed - " + "Logical Drive Failed\n", Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_OtherCauses: + DAC960_Progress("Consistency Check Failed - Other Causes\n", + Controller); + break; + case DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated: + DAC960_Progress("Consistency Check Successfully Terminated\n", + Controller); + break; + } + else if (NewEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress) + Controller->NeedConsistencyCheckProgress = true; + } + else if (CommandOpcode == DAC960_PerformEventLogOperation) + { + static char + *DAC960_EventMessages[] = + { "killed because write recovery failed", + "killed because of SCSI bus reset failure", + "killed because of double check condition", + "killed because it was removed", + "killed because of gross error on SCSI chip", + "killed because of bad tag returned from drive", + "killed because of timeout on SCSI command", + "killed because of reset SCSI command issued from system", + "killed because busy or parity error count exceeded limit", + "killed because of 'kill drive' command from system", + "killed because of selection timeout", + "killed due to SCSI phase sequence error", + "killed due to unknown status" }; + DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry; + if (EventLogEntry->SequenceNumber == + Controller->OldEventLogSequenceNumber) + { + unsigned char SenseKey = EventLogEntry->SenseKey; + unsigned char AdditionalSenseCode = + EventLogEntry->AdditionalSenseCode; + unsigned char AdditionalSenseCodeQualifier = + EventLogEntry->AdditionalSenseCodeQualifier; + if (SenseKey == 9 && + AdditionalSenseCode == 0x80 && + AdditionalSenseCodeQualifier < + sizeof(DAC960_EventMessages) / sizeof(char *)) + DAC960_Critical("Physical Drive %d:%d %s\n", Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + DAC960_EventMessages[ + AdditionalSenseCodeQualifier]); + else if (SenseKey == 6 && AdditionalSenseCode == 0x29) + { + if (Controller->MonitoringTimerCount > 0) + Controller->DeviceResetCount[EventLogEntry->Channel] + [EventLogEntry->TargetID]++; + } + else if (!(SenseKey == 0 || + (SenseKey == 2 && + AdditionalSenseCode == 0x04 && + (AdditionalSenseCodeQualifier == 0x01 || + AdditionalSenseCodeQualifier == 0x02)))) + { + DAC960_Critical("Physical Drive %d:%d Error Log: " + "Sense Key = %d, ASC = %02X, ASCQ = %02X\n", + Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + SenseKey, + AdditionalSenseCode, + AdditionalSenseCodeQualifier); + DAC960_Critical("Physical Drive %d:%d Error Log: " + "Information = %02X%02X%02X%02X " + "%02X%02X%02X%02X\n", + Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + EventLogEntry->Information[0], + EventLogEntry->Information[1], + EventLogEntry->Information[2], + EventLogEntry->Information[3], + EventLogEntry->CommandSpecificInformation[0], + EventLogEntry->CommandSpecificInformation[1], + EventLogEntry->CommandSpecificInformation[2], + EventLogEntry->CommandSpecificInformation[3]); + } + } + Controller->OldEventLogSequenceNumber++; + } + else if (CommandOpcode == DAC960_GetErrorTable) + { + DAC960_ErrorTable_T *OldErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex]; + DAC960_ErrorTable_T *NewErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex ^= 1]; + int Channel, TargetID; + for (Channel = 0; Channel < Controller->Channels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + DAC960_ErrorTableEntry_T *NewErrorEntry = + &NewErrorTable->ErrorTableEntries[Channel][TargetID]; + DAC960_ErrorTableEntry_T *OldErrorEntry = + &OldErrorTable->ErrorTableEntries[Channel][TargetID]; + if ((NewErrorEntry->ParityErrorCount != + OldErrorEntry->ParityErrorCount) || + (NewErrorEntry->SoftErrorCount != + OldErrorEntry->SoftErrorCount) || + (NewErrorEntry->HardErrorCount != + OldErrorEntry->HardErrorCount) || + (NewErrorEntry->MiscErrorCount != + OldErrorEntry->MiscErrorCount)) + DAC960_Critical("Physical Drive %d:%d Errors: " + "Parity = %d, Soft = %d, " + "Hard = %d, Misc = %d\n", + Controller, Channel, TargetID, + NewErrorEntry->ParityErrorCount, + NewErrorEntry->SoftErrorCount, + NewErrorEntry->HardErrorCount, + NewErrorEntry->MiscErrorCount); + } + } + else if (CommandOpcode == DAC960_GetDeviceState) + { + DAC960_DeviceState_T *OldDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + DAC960_DeviceState_T *NewDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex ^ 1] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + if (NewDeviceState->DeviceState != OldDeviceState->DeviceState) + DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller, + Controller->DeviceStateChannel, + Controller->DeviceStateTargetID, + (NewDeviceState->DeviceState == DAC960_Device_Dead + ? "DEAD" + : NewDeviceState->DeviceState + == DAC960_Device_WriteOnly + ? "WRITE-ONLY" + : NewDeviceState->DeviceState + == DAC960_Device_Online + ? "ONLINE" : "STANDBY")); + if (OldDeviceState->DeviceState == DAC960_Device_Dead && + NewDeviceState->DeviceState != DAC960_Device_Dead) + { + Controller->NeedDeviceInquiryInformation = true; + Controller->NeedDeviceSerialNumberInformation = true; + } + } + else if (CommandOpcode == DAC960_GetLogicalDriveInformation) + { + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + { + DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber]; + DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex ^ 1] + [LogicalDriveNumber]; + if (NewLogicalDriveInformation->LogicalDriveState != + OldLogicalDriveInformation->LogicalDriveState) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "is now %s\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (NewLogicalDriveInformation->LogicalDriveState + == DAC960_LogicalDrive_Online + ? "ONLINE" + : NewLogicalDriveInformation->LogicalDriveState + == DAC960_LogicalDrive_Critical + ? "CRITICAL" : "OFFLINE")); + if (NewLogicalDriveInformation->WriteBack != + OldLogicalDriveInformation->WriteBack) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "is now %s\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (NewLogicalDriveInformation->WriteBack + ? "WRITE BACK" : "WRITE THRU")); + } + Controller->LogicalDriveInformationIndex ^= 1; + } + else if (CommandOpcode == DAC960_GetRebuildProgress) + { + unsigned int LogicalDriveNumber = + Controller->RebuildProgress.LogicalDriveNumber; + unsigned int LogicalDriveSize = + Controller->RebuildProgress.LogicalDriveSize; + unsigned int BlocksCompleted = + LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks; + switch (CommandStatus) + { + case DAC960_NormalCompletion: + Controller->EphemeralProgressMessage = true; + DAC960_Progress("Rebuild in Progress: " + "Logical Drive %d (/dev/rd/c%dd%d) " + "%d%% completed\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (100 * (BlocksCompleted >> 7)) + / (LogicalDriveSize >> 7)); + Controller->EphemeralProgressMessage = false; + break; + case DAC960_RebuildFailed_LogicalDriveFailure: + DAC960_Progress("Rebuild Failed due to " + "Logical Drive Failure\n", Controller); + break; + case DAC960_RebuildFailed_BadBlocksOnOther: + DAC960_Progress("Rebuild Failed due to " + "Bad Blocks on Other Drives\n", Controller); + break; + case DAC960_RebuildFailed_NewDriveFailed: + DAC960_Progress("Rebuild Failed due to " + "Failure of Drive Being Rebuilt\n", Controller); + break; + case DAC960_NoRebuildOrCheckInProgress: + if (Controller->LastRebuildStatus != DAC960_NormalCompletion) + break; + case DAC960_RebuildSuccessful: + DAC960_Progress("Rebuild Completed Successfully\n", Controller); + break; + } + Controller->LastRebuildStatus = CommandStatus; + } + else if (CommandOpcode == DAC960_RebuildStat) + { + unsigned int LogicalDriveNumber = + Controller->RebuildProgress.LogicalDriveNumber; + unsigned int LogicalDriveSize = + Controller->RebuildProgress.LogicalDriveSize; + unsigned int BlocksCompleted = + LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks; + if (CommandStatus == DAC960_NormalCompletion) + { + Controller->EphemeralProgressMessage = true; + DAC960_Progress("Consistency Check in Progress: " + "Logical Drive %d (/dev/rd/c%dd%d) " + "%d%% completed\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (100 * (BlocksCompleted >> 7)) + / (LogicalDriveSize >> 7)); + Controller->EphemeralProgressMessage = false; + } + } + } + if (CommandType == DAC960_MonitoringCommand) + { + if (Controller->NewEventLogSequenceNumber + - Controller->OldEventLogSequenceNumber > 0) + { + Command->CommandMailbox.Type3E.CommandOpcode = + DAC960_PerformEventLogOperation; + Command->CommandMailbox.Type3E.OperationType = + DAC960_GetEventLogEntry; + Command->CommandMailbox.Type3E.OperationQualifier = 1; + Command->CommandMailbox.Type3E.SequenceNumber = + Controller->OldEventLogSequenceNumber; + Command->CommandMailbox.Type3E.BusAddress = + Virtual_to_Bus(&Controller->EventLogEntry); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedErrorTableInformation) + { + Controller->NeedErrorTableInformation = false; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_GetErrorTable; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus( + &Controller->ErrorTable[Controller->ErrorTableIndex ^ 1]); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedRebuildProgress && + Controller->Enquiry[Controller->EnquiryIndex] + .CriticalLogicalDriveCount < + Controller->Enquiry[Controller->EnquiryIndex ^ 1] + .CriticalLogicalDriveCount) + { + Controller->NeedRebuildProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetRebuildProgress; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedDeviceStateInformation) + { + if (Controller->NeedDeviceInquiryInformation) + { + DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB; + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->InquiryStandardData + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + InquiryStandardData->PeripheralDeviceType = 0x1F; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB; + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + DCDB->Channel = Controller->DeviceStateChannel; + DCDB->TargetID = Controller->DeviceStateTargetID; + DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem; + DCDB->EarlyStatus = false; + DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds; + DCDB->NoAutomaticRequestSense = false; + DCDB->DisconnectPermitted = true; + DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData); + DCDB->CDBLength = 6; + DCDB->TransferLengthHigh4 = 0; + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 0; /* EVPD = 0 */ + DCDB->CDB[2] = 0; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_QueueCommand(Command); + Controller->NeedDeviceInquiryInformation = false; + return; + } + if (Controller->NeedDeviceSerialNumberInformation) + { + DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + &Controller->InquiryUnitSerialNumber + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB; + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + DCDB->Channel = Controller->DeviceStateChannel; + DCDB->TargetID = Controller->DeviceStateTargetID; + DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem; + DCDB->EarlyStatus = false; + DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds; + DCDB->NoAutomaticRequestSense = false; + DCDB->DisconnectPermitted = true; + DCDB->TransferLength = + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber); + DCDB->CDBLength = 6; + DCDB->TransferLengthHigh4 = 0; + DCDB->SenseLength = sizeof(DCDB->SenseData); + DCDB->CDB[0] = 0x12; /* INQUIRY */ + DCDB->CDB[1] = 1; /* EVPD = 1 */ + DCDB->CDB[2] = 0x80; /* Page Code */ + DCDB->CDB[3] = 0; /* Reserved */ + DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + DCDB->CDB[5] = 0; /* Control */ + DAC960_QueueCommand(Command); + Controller->NeedDeviceSerialNumberInformation = false; + return; + } + if (++Controller->DeviceStateTargetID == DAC960_MaxTargets) + { + Controller->DeviceStateChannel++; + Controller->DeviceStateTargetID = 0; + } + while (Controller->DeviceStateChannel < Controller->Channels) + { + DAC960_DeviceState_T *OldDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + if (OldDeviceState->Present && + OldDeviceState->DeviceType == DAC960_DiskType) + { + Command->CommandMailbox.Type3D.CommandOpcode = + DAC960_GetDeviceState; + Command->CommandMailbox.Type3D.Channel = + Controller->DeviceStateChannel; + Command->CommandMailbox.Type3D.TargetID = + Controller->DeviceStateTargetID; + Command->CommandMailbox.Type3D.BusAddress = + Virtual_to_Bus(&Controller->DeviceState + [Controller->DeviceStateIndex ^ 1] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]); + DAC960_QueueCommand(Command); + return; + } + if (++Controller->DeviceStateTargetID == DAC960_MaxTargets) + { + Controller->DeviceStateChannel++; + Controller->DeviceStateTargetID = 0; + } + } + Controller->NeedDeviceStateInformation = false; + Controller->DeviceStateIndex ^= 1; + } + if (Controller->NeedLogicalDriveInformation) + { + Controller->NeedLogicalDriveInformation = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetLogicalDriveInformation; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus( + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex ^ 1]); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedRebuildProgress) + { + Controller->NeedRebuildProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetRebuildProgress; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedConsistencyCheckProgress) + { + Controller->NeedConsistencyCheckProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_RebuildStat; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + Controller->MonitoringTimerCount++; + Controller->MonitoringTimer.expires = + jiffies + DAC960_MonitoringTimerInterval; + add_timer(&Controller->MonitoringTimer); + } + if (CommandType == DAC960_ImmediateCommand) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + return; + } + if (CommandType == DAC960_QueuedCommand) + { + DAC960_KernelCommand_T *KernelCommand = Command->KernelCommand; + KernelCommand->CommandStatus = CommandStatus; + Command->KernelCommand = NULL; + if (CommandOpcode == DAC960_DCDB) + Controller->DirectCommandActive[KernelCommand->DCDB->Channel] + [KernelCommand->DCDB->TargetID] = false; + DAC960_DeallocateCommand(Command); + KernelCommand->CompletionFunction(KernelCommand); + return; + } + /* + Queue a Status Monitoring Command to the Controller using the just + completed Command if one was deferred previously due to lack of a + free Command when the Monitoring Timer Function was called. + */ + if (Controller->MonitoringCommandDeferred) + { + Controller->MonitoringCommandDeferred = false; + DAC960_QueueMonitoringCommand(Command); + return; + } + /* + Deallocate the Command, and wake up any processes waiting on a free Command. + */ + DAC960_DeallocateCommand(Command); + wake_up(&Controller->CommandWaitQueue); +} + + +/* + DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers. +*/ + +static void DAC960_InterruptHandler(int IRQ_Channel, + void *DeviceIdentifier, + Registers_T *InterruptRegisters) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_StatusMailbox_T *NextStatusMailbox; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags); + /* + Process Hardware Interrupts for Controller. + */ + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + DAC960_V5_AcknowledgeInterrupt(ControllerBaseAddress); + NextStatusMailbox = Controller->NextStatusMailbox; + while (NextStatusMailbox->Fields.Valid) + { + DAC960_CommandIdentifier_T CommandIdentifier = + NextStatusMailbox->Fields.CommandIdentifier; + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus; + NextStatusMailbox->Word = 0; + if (++NextStatusMailbox > Controller->LastStatusMailbox) + NextStatusMailbox = Controller->FirstStatusMailbox; + DAC960_ProcessCompletedCommand(Command); + } + Controller->NextStatusMailbox = NextStatusMailbox; + break; + case DAC960_V4_Controller: + DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress); + NextStatusMailbox = Controller->NextStatusMailbox; + while (NextStatusMailbox->Fields.Valid) + { + DAC960_CommandIdentifier_T CommandIdentifier = + NextStatusMailbox->Fields.CommandIdentifier; + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus; + NextStatusMailbox->Word = 0; + if (++NextStatusMailbox > Controller->LastStatusMailbox) + NextStatusMailbox = Controller->FirstStatusMailbox; + DAC960_ProcessCompletedCommand(Command); + } + Controller->NextStatusMailbox = NextStatusMailbox; + break; + case DAC960_V3_Controller: + while (DAC960_V3_StatusAvailableP(ControllerBaseAddress)) + { + DAC960_CommandIdentifier_T CommandIdentifier = + DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress); + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = + DAC960_V3_ReadStatusRegister(ControllerBaseAddress); + DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress); + DAC960_V3_AcknowledgeStatus(ControllerBaseAddress); + DAC960_ProcessCompletedCommand(Command); + } + break; + } + /* + Attempt to remove additional I/O Requests from the Controller's + I/O Request Queue and queue them to the Controller. + */ + while (DAC960_ProcessRequest(Controller, false)) ; + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags); +} + + +/* + DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller. +*/ + +static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_MonitoringCommand; + CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry; + CommandMailbox->Type3.BusAddress = + Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]); + DAC960_QueueCommand(Command); +} + + +/* + DAC960_MonitoringTimerFunction is the timer function for monitoring + the status of DAC960 Controllers. +*/ + +static void DAC960_MonitoringTimerFunction(unsigned long TimerData) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData; + DAC960_Command_T *Command; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + /* + Queue a Status Monitoring Command to Controller. + */ + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) + DAC960_QueueMonitoringCommand(Command); + else Controller->MonitoringCommandDeferred = true; + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); +} + + +/* + DAC960_Open is the Device Open Function for the DAC960 Driver. +*/ + +static int DAC960_Open(Inode_T *Inode, File_T *File) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DAC960_Controller_T *Controller; + if (ControllerNumber == 0 && LogicalDriveNumber == 0 && + (File->f_flags & O_NONBLOCK)) + goto ModuleOnly; + if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL || + LogicalDriveNumber > Controller->LogicalDriveCount - 1) + return -ENXIO; + if (Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber].LogicalDriveState + == DAC960_LogicalDrive_Offline) + return -ENXIO; + if (Controller->LogicalDriveInitialState[LogicalDriveNumber] + == DAC960_LogicalDrive_Offline) + { + Controller->LogicalDriveInitialState[LogicalDriveNumber] = + DAC960_LogicalDrive_Online; + DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + } + if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0) + return -ENXIO; + /* + Increment Controller and Logical Drive Usage Counts. + */ + Controller->ControllerUsageCount++; + Controller->LogicalDriveUsageCount[LogicalDriveNumber]++; + ModuleOnly: + MOD_INC_USE_COUNT; + return 0; +} + + +/* + DAC960_Release is the Device Release Function for the DAC960 Driver. +*/ + +static int DAC960_Release(Inode_T *Inode, File_T *File) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + if (ControllerNumber == 0 && LogicalDriveNumber == 0 && + File != NULL && (File->f_flags & O_NONBLOCK)) + goto ModuleOnly; + /* + Force any buffered data to be written. + */ + fsync_dev(Inode->i_rdev); + /* + Decrement the Logical Drive and Controller Usage Counts. + */ + Controller->LogicalDriveUsageCount[LogicalDriveNumber]--; + Controller->ControllerUsageCount--; + ModuleOnly: + MOD_DEC_USE_COUNT; + return 0; +} + + +/* + DAC960_IOCTL is the Device IOCTL Function for the DAC960 Driver. +*/ + +static int DAC960_IOCTL(Inode_T *Inode, File_T *File, + unsigned int Request, unsigned long Argument) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DiskGeometry_T Geometry, *UserGeometry; + DAC960_Controller_T *Controller; + int PartitionNumber; + if (File->f_flags & O_NONBLOCK) + return DAC960_UserIOCTL(Inode, File, Request, Argument); + if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL || + LogicalDriveNumber > Controller->LogicalDriveCount - 1) + return -ENXIO; + switch (Request) + { + case HDIO_GETGEO: + /* Get BIOS Disk Geometry. */ + UserGeometry = (DiskGeometry_T *) Argument; + if (UserGeometry == NULL) return -EINVAL; + Geometry.heads = Controller->GeometryTranslationHeads; + Geometry.sectors = Controller->GeometryTranslationSectors; + Geometry.cylinders = + Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber].LogicalDriveSize + / (Controller->GeometryTranslationHeads * + Controller->GeometryTranslationSectors); + Geometry.start = Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)] + .start_sect; + return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T)); + case BLKGETSIZE: + /* Get Device Size. */ + if ((long *) Argument == NULL) return -EINVAL; + return put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)] + .nr_sects, + (long *) Argument); + case BLKRAGET: + /* Get Read-Ahead. */ + if ((int *) Argument == NULL) return -EINVAL; + return put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument); + case BLKRASET: + /* Set Read-Ahead. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (Argument > 256) return -EINVAL; + read_ahead[MAJOR(Inode->i_rdev)] = Argument; + return 0; + case BLKFLSBUF: + /* Flush Buffers. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + fsync_dev(Inode->i_rdev); + invalidate_buffers(Inode->i_rdev); + return 0; + case BLKRRPART: + /* Re-Read Partition Table. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1) + return -EBUSY; + for (PartitionNumber = 0; + PartitionNumber < DAC960_MaxPartitions; + PartitionNumber++) + { + KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber, + LogicalDriveNumber, + PartitionNumber); + int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, + PartitionNumber); + SuperBlock_T *SuperBlock = get_super(Device); + if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0) + continue; + /* + Flush all changes and invalidate buffered state. + */ + sync_dev(Device); + if (SuperBlock != NULL) + invalidate_inodes(SuperBlock); + invalidate_buffers(Device); + /* + Clear existing partition sizes. + */ + if (PartitionNumber > 0) + { + Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0; + Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0; + } + /* + Reset the Block Size so that the partition table can be read. + */ + set_blocksize(Device, BLOCK_SIZE); + } + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + return 0; + } + return -EINVAL; +} + + +/* + DAC960_UserIOCTL is the User IOCTL Function for the DAC960 Driver. +*/ + +static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File, + unsigned int Request, unsigned long Argument) +{ + int ErrorCode; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + switch (Request) + { + case DAC960_IOCTL_GET_CONTROLLER_COUNT: + return DAC960_ControllerCount; + case DAC960_IOCTL_GET_CONTROLLER_INFO: + { + DAC960_ControllerInfo_T *UserSpaceControllerInfo = + (DAC960_ControllerInfo_T *) Argument; + DAC960_ControllerInfo_T ControllerInfo; + DAC960_Controller_T *Controller; + int ControllerNumber; + if (UserSpaceControllerInfo == NULL) return -EINVAL; + ErrorCode = get_user(ControllerNumber, + &UserSpaceControllerInfo->ControllerNumber); + if (ErrorCode != 0) return ErrorCode; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); + ControllerInfo.ControllerNumber = ControllerNumber; + ControllerInfo.PCI_Bus = Controller->Bus; + ControllerInfo.PCI_Device = Controller->Device; + ControllerInfo.PCI_Function = Controller->Function; + ControllerInfo.IRQ_Channel = Controller->IRQ_Channel; + ControllerInfo.Channels = Controller->Channels; + ControllerInfo.PCI_Address = Controller->PCI_Address; + strcpy(ControllerInfo.ModelName, Controller->ModelName); + strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); + return copy_to_user(UserSpaceControllerInfo, &ControllerInfo, + sizeof(DAC960_ControllerInfo_T)); + } + case DAC960_IOCTL_EXECUTE_COMMAND: + { + DAC960_UserCommand_T *UserSpaceUserCommand = + (DAC960_UserCommand_T *) Argument; + DAC960_UserCommand_T UserCommand; + DAC960_Controller_T *Controller; + DAC960_Command_T *Command = NULL; + DAC960_CommandOpcode_T CommandOpcode; + DAC960_CommandStatus_T CommandStatus; + DAC960_DCDB_T DCDB; + ProcessorFlags_T ProcessorFlags; + int ControllerNumber, DataTransferLength; + unsigned char *DataTransferBuffer = NULL; + if (UserSpaceUserCommand == NULL) return -EINVAL; + ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand, + sizeof(DAC960_UserCommand_T)); + if (ErrorCode != 0) goto Failure; + ControllerNumber = UserCommand.ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; + DataTransferLength = UserCommand.DataTransferLength; + if (CommandOpcode & 0x80) return -EINVAL; + if (CommandOpcode == DAC960_DCDB) + { + ErrorCode = + copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_DCDB_T)); + if (ErrorCode != 0) goto Failure; + if (!((DataTransferLength == 0 && + DCDB.Direction == DAC960_DCDB_NoDataTransfer) || + (DataTransferLength > 0 && + DCDB.Direction == DAC960_DCDB_DataTransferDeviceToSystem) || + (DataTransferLength < 0 && + DCDB.Direction == DAC960_DCDB_DataTransferSystemToDevice))) + return -EINVAL; + if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) + != abs(DataTransferLength)) + return -EINVAL; + } + if (DataTransferLength > 0) + { + DataTransferBuffer = kmalloc(DataTransferLength, GFP_KERNEL); + if (DataTransferBuffer == NULL) return -ENOMEM; + memset(DataTransferBuffer, 0, DataTransferLength); + } + else if (DataTransferLength < 0) + { + DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL); + if (DataTransferBuffer == NULL) return -ENOMEM; + ErrorCode = copy_from_user(DataTransferBuffer, + UserCommand.DataTransferBuffer, + -DataTransferLength); + if (ErrorCode != 0) goto Failure; + } + if (CommandOpcode == DAC960_DCDB) + { + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + if (!Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID]) + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) + Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID] = true; + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(&DCDB); + DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer); + } + else + { + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + if (DataTransferBuffer != NULL) + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(DataTransferBuffer); + } + DAC960_ExecuteCommand(Command); + CommandStatus = Command->CommandStatus; + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_DeallocateCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (CommandStatus == DAC960_NormalCompletion && + DataTransferLength > 0) + { + ErrorCode = copy_to_user(UserCommand.DataTransferBuffer, + DataTransferBuffer, DataTransferLength); + if (ErrorCode != 0) goto Failure; + } + if (CommandOpcode == DAC960_DCDB) + { + Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID] = false; + ErrorCode = + copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_DCDB_T)); + if (ErrorCode != 0) goto Failure; + } + ErrorCode = CommandStatus; + Failure: + if (DataTransferBuffer != NULL) + kfree(DataTransferBuffer); + return ErrorCode; + } + } + return -EINVAL; +} + + +/* + DAC960_KernelIOCTL is the Kernel IOCTL Function for the DAC960 Driver. +*/ + +int DAC960_KernelIOCTL(unsigned int Request, void *Argument) +{ + switch (Request) + { + case DAC960_IOCTL_GET_CONTROLLER_COUNT: + return DAC960_ControllerCount; + case DAC960_IOCTL_GET_CONTROLLER_INFO: + { + DAC960_ControllerInfo_T *ControllerInfo = + (DAC960_ControllerInfo_T *) Argument; + DAC960_Controller_T *Controller; + int ControllerNumber; + if (ControllerInfo == NULL) return -EINVAL; + ControllerNumber = ControllerInfo->ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + memset(ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); + ControllerInfo->ControllerNumber = ControllerNumber; + ControllerInfo->PCI_Bus = Controller->Bus; + ControllerInfo->PCI_Device = Controller->Device; + ControllerInfo->PCI_Function = Controller->Function; + ControllerInfo->IRQ_Channel = Controller->IRQ_Channel; + ControllerInfo->Channels = Controller->Channels; + ControllerInfo->PCI_Address = Controller->PCI_Address; + strcpy(ControllerInfo->ModelName, Controller->ModelName); + strcpy(ControllerInfo->FirmwareVersion, Controller->FirmwareVersion); + return 0; + } + case DAC960_IOCTL_EXECUTE_COMMAND: + { + DAC960_KernelCommand_T *KernelCommand = + (DAC960_KernelCommand_T *) Argument; + DAC960_Controller_T *Controller; + DAC960_Command_T *Command = NULL; + DAC960_CommandOpcode_T CommandOpcode; + DAC960_DCDB_T *DCDB = NULL; + ProcessorFlags_T ProcessorFlags; + int ControllerNumber, DataTransferLength; + unsigned char *DataTransferBuffer = NULL; + if (KernelCommand == NULL) return -EINVAL; + ControllerNumber = KernelCommand->ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + CommandOpcode = KernelCommand->CommandMailbox.Common.CommandOpcode; + DataTransferLength = KernelCommand->DataTransferLength; + DataTransferBuffer = KernelCommand->DataTransferBuffer; + if (CommandOpcode & 0x80) return -EINVAL; + if (CommandOpcode == DAC960_DCDB) + { + DCDB = KernelCommand->DCDB; + if (!((DataTransferLength == 0 && + DCDB->Direction == DAC960_DCDB_NoDataTransfer) || + (DataTransferLength > 0 && + DCDB->Direction == DAC960_DCDB_DataTransferDeviceToSystem) || + (DataTransferLength < 0 && + DCDB->Direction == DAC960_DCDB_DataTransferSystemToDevice))) + return -EINVAL; + if (((DCDB->TransferLengthHigh4 << 16) | DCDB->TransferLength) + != abs(DataTransferLength)) + return -EINVAL; + } + if (DataTransferLength != 0 && DataTransferBuffer == NULL) + return -EINVAL; + if (DataTransferLength > 0) + memset(DataTransferBuffer, 0, DataTransferLength); + if (CommandOpcode == DAC960_DCDB) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + if (!Controller->DirectCommandActive[DCDB->Channel] + [DCDB->TargetID]) + Command = DAC960_AllocateCommand(Controller); + if (Command == NULL) + { + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return -EBUSY; + } + else Controller->DirectCommandActive[DCDB->Channel] + [DCDB->TargetID] = true; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_QueuedCommand; + memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + Command->KernelCommand = KernelCommand; + DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + else + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + if (Command == NULL) + { + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return -EBUSY; + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_QueuedCommand; + memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + if (DataTransferBuffer != NULL) + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(DataTransferBuffer); + Command->KernelCommand = KernelCommand; + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + return 0; + } + } + return -EINVAL; +} + + +/* + DAC960_GenericDiskInit is the Generic Disk Information Initialization + Function for the DAC960 Driver. +*/ + +static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo) +{ + DAC960_Controller_T *Controller = + (DAC960_Controller_T *) GenericDiskInfo->real_devices; + DAC960_LogicalDriveInformation_T *LogicalDriveInformation = + Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex]; + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects = + LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize; +} + + +/* + DAC960_Message prints Driver Messages. +*/ + +static void DAC960_Message(DAC960_MessageLevel_T MessageLevel, + char *Format, + DAC960_Controller_T *Controller, + ...) +{ + static char Buffer[DAC960_LineBufferSize]; + static boolean BeginningOfLine = true; + va_list Arguments; + int Length = 0; + va_start(Arguments, Controller); + Length = vsprintf(Buffer, Format, Arguments); + va_end(Arguments); + if (Controller == NULL) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + DAC960_ControllerCount, Buffer); + else if (MessageLevel == DAC960_AnnounceLevel || + MessageLevel == DAC960_InfoLevel) + { + if (!Controller->ControllerInitialized) + { + strcpy(&Controller->InitialStatusBuffer[ + Controller->InitialStatusLength], Buffer); + Controller->InitialStatusLength += Length; + if (MessageLevel == DAC960_AnnounceLevel) + { + static int AnnouncementLines = 0; + if (++AnnouncementLines <= 2) + printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], + Buffer); + } + else + { + if (BeginningOfLine) + { + if (Buffer[0] != '\n' || Length > 1) + printk("%sDAC960#%d: %s", + DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else printk("%s", Buffer); + } + } + else + { + strcpy(&Controller->CurrentStatusBuffer[ + Controller->CurrentStatusLength], Buffer); + Controller->CurrentStatusLength += Length; + } + } + else if (MessageLevel == DAC960_ProgressLevel) + { + strcpy(Controller->RebuildProgressBuffer, Buffer); + Controller->RebuildProgressLength = Length; + if (Controller->EphemeralProgressMessage) + { + if (jiffies - Controller->LastProgressReportTime + >= DAC960_ProgressReportingInterval) + { + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + Controller->LastProgressReportTime = jiffies; + } + } + else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else if (MessageLevel == DAC960_UserCriticalLevel) + { + strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength], + Buffer); + Controller->UserStatusLength += Length; + if (Buffer[0] != '\n' || Length > 1) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else + { + if (BeginningOfLine) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + else printk("%s", Buffer); + } + BeginningOfLine = (Buffer[Length-1] == '\n'); +} + + +/* + DAC960_ParsePhysicalDrive parses spaces followed by a Physical Drive + Channel:TargetID specification from a User Command string. It updates + Channel and TargetID and returns true on success and returns false otherwise. +*/ + +static boolean DAC960_ParsePhysicalDrive(DAC960_Controller_T *Controller, + char *UserCommandString, + unsigned char *Channel, + unsigned char *TargetID) +{ + char *NewUserCommandString = UserCommandString; + unsigned long XChannel, XTargetID; + while (*UserCommandString == ' ') UserCommandString++; + if (UserCommandString == NewUserCommandString) + return false; + XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != ':' || + XChannel >= Controller->Channels) + return false; + UserCommandString = ++NewUserCommandString; + XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != '\0' || + XTargetID >= DAC960_MaxTargets) + return false; + *Channel = XChannel; + *TargetID = XTargetID; + return true; +} + + +/* + DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number + specification from a User Command string. It updates LogicalDriveNumber and + returns true on success and returns false otherwise. +*/ + +static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller, + char *UserCommandString, + unsigned char *LogicalDriveNumber) +{ + char *NewUserCommandString = UserCommandString; + unsigned long XLogicalDriveNumber; + while (*UserCommandString == ' ') UserCommandString++; + if (UserCommandString == NewUserCommandString) + return false; + XLogicalDriveNumber = + simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != '\0' || + XLogicalDriveNumber >= Controller->LogicalDriveCount) + return false; + *LogicalDriveNumber = XLogicalDriveNumber; + return true; +} + + +/* + DAC960_SetDeviceState sets the Device State for a Physical Drive. +*/ + +static void DAC960_SetDeviceState(DAC960_Controller_T *Controller, + DAC960_Command_T *Command, + unsigned char Channel, + unsigned char TargetID, + DAC960_PhysicalDeviceState_T DeviceState, + const char *DeviceStateString) +{ + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + CommandMailbox->Type3D.CommandOpcode = DAC960_StartDevice; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + CommandMailbox->Type3D.DeviceState = DeviceState; + CommandMailbox->Type3D.Modifier = 0; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("%s of Physical Drive %d:%d Succeeded\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_UnableToStartDevice: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Unable to Start Device\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_NoDeviceAtAddress: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "No Device at Address\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_InvalidChannelOrTargetOrModifier: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Invalid Channel or Target or Modifier\n", + Controller, DeviceStateString, Channel, TargetID); + break; + case DAC960_ChannelBusy: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Channel Busy\n", Controller, + DeviceStateString, Channel, TargetID); + break; + default: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Unexpected Status %04X\n", Controller, + DeviceStateString, Channel, TargetID, + Command->CommandStatus); + break; + } +} + + +/* + DAC960_ExecuteUserCommand executes a User Command. +*/ + +static boolean DAC960_ExecuteUserCommand(DAC960_Controller_T *Controller, + char *UserCommand) +{ + DAC960_Command_T *Command; + DAC960_CommandMailbox_T *CommandMailbox; + ProcessorFlags_T ProcessorFlags; + unsigned char Channel, TargetID, LogicalDriveNumber; + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + Controller->UserStatusLength = 0; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox = &Command->CommandMailbox; + if (strcmp(UserCommand, "flush-cache") == 0) + { + CommandMailbox->Type3.CommandOpcode = DAC960_Flush; + DAC960_ExecuteCommand(Command); + DAC960_UserCritical("Cache Flush Completed\n", Controller); + } + else if (strncmp(UserCommand, "kill", 4) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[4], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState != DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Dead, "Kill"); + else DAC960_UserCritical("Kill of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + } + else if (strncmp(UserCommand, "make-online", 11) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[11], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState == DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Online, "Make Online"); + else DAC960_UserCritical("Make Online of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + + } + else if (strncmp(UserCommand, "make-standby", 12) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[12], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState == DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Standby, "Make Standby"); + else DAC960_UserCritical("Make Standby of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + } + else if (strncmp(UserCommand, "rebuild", 7) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[7], + &Channel, &TargetID)) + { + CommandMailbox->Type3D.CommandOpcode = DAC960_RebuildAsync; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Initiated\n", + Controller, Channel, TargetID); + break; + case DAC960_AttemptToRebuildOnlineDrive: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Attempt to Rebuild Online or " + "Unresponsive Drive\n", + Controller, Channel, TargetID); + break; + case DAC960_NewDiskFailedDuringRebuild: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "New Disk Failed During Rebuild\n", + Controller, Channel, TargetID); + break; + case DAC960_InvalidDeviceAddress: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Invalid Device Address\n", + Controller, Channel, TargetID); + break; + case DAC960_RebuildOrCheckAlreadyInProgress: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Rebuild or Consistency Check Already " + "in Progress\n", Controller, Channel, TargetID); + break; + default: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Unexpected Status %04X\n", Controller, + Channel, TargetID, Command->CommandStatus); + break; + } + } + else if (strncmp(UserCommand, "check-consistency", 17) == 0 && + DAC960_ParseLogicalDrive(Controller, &UserCommand[17], + &LogicalDriveNumber)) + { + CommandMailbox->Type3C.CommandOpcode = DAC960_CheckConsistencyAsync; + CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber; + CommandMailbox->Type3C.AutoRestore = true; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Initiated\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_DependentDiskIsDead: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Dependent Physical Drive is DEAD\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_InvalidOrNonredundantLogicalDrive: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Invalid or Nonredundant Logical Drive\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_RebuildOrCheckAlreadyInProgress: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - Rebuild or " + "Consistency Check Already in Progress\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + default: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Unexpected Status %04X\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, Command->CommandStatus); + break; + } + } + else if (strcmp(UserCommand, "cancel-rebuild") == 0 || + strcmp(UserCommand, "cancel-consistency-check") == 0) + { + unsigned char OldRebuildRateConstant; + CommandMailbox->Type3R.CommandOpcode = DAC960_RebuildControl; + CommandMailbox->Type3R.RebuildRateConstant = 0xFF; + CommandMailbox->Type3R.BusAddress = + Virtual_to_Bus(&OldRebuildRateConstant); + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n", + Controller); + break; + default: + DAC960_UserCritical("Cancellation of Rebuild or " + "Consistency Check Failed - " + "Unexpected Status %04X\n", + Controller, Command->CommandStatus); + break; + } + } + else DAC960_UserCritical("Illegal User Command: '%s'\n", + Controller, UserCommand); + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_DeallocateCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return true; +} + + +/* + DAC960_ProcReadStatus implements reading /proc/rd/status. +*/ + +static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + char *StatusMessage = "OK\n"; + int ControllerNumber, BytesAvailable; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + DAC960_Enquiry_T *Enquiry; + if (Controller == NULL) continue; + Enquiry = &Controller->Enquiry[Controller->EnquiryIndex]; + if (Enquiry->CriticalLogicalDriveCount > 0 || + Enquiry->OfflineLogicalDriveCount > 0 || + Enquiry->DeadDriveCount > 0) + { + StatusMessage = "ALERT\n"; + break; + } + } + BytesAvailable = strlen(StatusMessage) - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &StatusMessage[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status. +*/ + +static int DAC960_ProcReadInitialStatus(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable = Controller->InitialStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &Controller->InitialStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status. +*/ + +static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable; + if (jiffies != Controller->LastCurrentStatusTime) + { + Controller->CurrentStatusLength = 0; + DAC960_AnnounceDriver(Controller); + DAC960_ReportControllerConfiguration(Controller); + DAC960_ReportDeviceConfiguration(Controller); + Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; + Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; + if (Controller->RebuildProgressLength > 0) + { + strcpy(&Controller->CurrentStatusBuffer + [Controller->CurrentStatusLength], + Controller->RebuildProgressBuffer); + Controller->CurrentStatusLength += Controller->RebuildProgressLength; + } + else + { + char *StatusMessage = "No Rebuild or Consistency Check in Progress\n"; + strcpy(&Controller->CurrentStatusBuffer + [Controller->CurrentStatusLength], + StatusMessage); + Controller->CurrentStatusLength += strlen(StatusMessage); + } + Controller->LastCurrentStatusTime = jiffies; + } + BytesAvailable = Controller->CurrentStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &Controller->CurrentStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command. +*/ + +static int DAC960_ProcReadUserCommand(char *Page, char **Start, off_t Offset, + int Count, int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable = Controller->UserStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + *Start = Page; + memcpy(Page, &Controller->UserStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command. +*/ + +static int DAC960_ProcWriteUserCommand(File_T *File, const char *Buffer, + unsigned long Count, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + char CommandBuffer[80]; + int Length; + if (Count > sizeof(CommandBuffer)-1) return -EINVAL; + copy_from_user(CommandBuffer, Buffer, Count); + CommandBuffer[Count] = '\0'; + Length = strlen(CommandBuffer); + if (CommandBuffer[Length-1] == '\n') + CommandBuffer[--Length] = '\0'; + return (DAC960_ExecuteUserCommand(Controller, CommandBuffer) + ? Count : -EBUSY); +} + + +/* + DAC960_CreateProcEntries creates the /proc/rd/... entries for the DAC960 + Driver. +*/ + +static void DAC960_CreateProcEntries(void) +{ + static PROC_DirectoryEntry_T StatusProcEntry; + int ControllerNumber; + DAC960_ProcDirectoryEntry.name = "rd"; + DAC960_ProcDirectoryEntry.namelen = strlen(DAC960_ProcDirectoryEntry.name); + DAC960_ProcDirectoryEntry.mode = S_IFDIR | S_IRUGO | S_IXUGO; + proc_register(&proc_root, &DAC960_ProcDirectoryEntry); + StatusProcEntry.name = "status"; + StatusProcEntry.namelen = strlen(StatusProcEntry.name); + StatusProcEntry.mode = S_IFREG | S_IRUGO; + StatusProcEntry.read_proc = DAC960_ProcReadStatus; + proc_register(&DAC960_ProcDirectoryEntry, &StatusProcEntry); + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry; + PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry; + if (Controller == NULL) continue; + ControllerProcEntry = &Controller->ControllerProcEntry; + ControllerProcEntry->name = Controller->ControllerName; + ControllerProcEntry->namelen = strlen(ControllerProcEntry->name); + ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO; + proc_register(&DAC960_ProcDirectoryEntry, ControllerProcEntry); + InitialStatusProcEntry = &Controller->InitialStatusProcEntry; + InitialStatusProcEntry->name = "initial_status"; + InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name); + InitialStatusProcEntry->mode = S_IFREG | S_IRUGO; + InitialStatusProcEntry->data = Controller; + InitialStatusProcEntry->read_proc = DAC960_ProcReadInitialStatus; + proc_register(ControllerProcEntry, InitialStatusProcEntry); + CurrentStatusProcEntry = &Controller->CurrentStatusProcEntry; + CurrentStatusProcEntry->name = "current_status"; + CurrentStatusProcEntry->namelen = strlen(CurrentStatusProcEntry->name); + CurrentStatusProcEntry->mode = S_IFREG | S_IRUGO; + CurrentStatusProcEntry->data = Controller; + CurrentStatusProcEntry->read_proc = DAC960_ProcReadCurrentStatus; + proc_register(ControllerProcEntry, CurrentStatusProcEntry); + UserCommandProcEntry = &Controller->UserCommandProcEntry; + UserCommandProcEntry->name = "user_command"; + UserCommandProcEntry->namelen = strlen(UserCommandProcEntry->name); + UserCommandProcEntry->mode = S_IFREG | S_IWUSR | S_IRUSR; + UserCommandProcEntry->data = Controller; + UserCommandProcEntry->read_proc = DAC960_ProcReadUserCommand; + UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand; + proc_register(ControllerProcEntry, UserCommandProcEntry); + } +} + + +/* + DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the DAC960 + Driver. +*/ + +static void DAC960_DestroyProcEntries(void) +{ + proc_unregister(&proc_root, DAC960_ProcDirectoryEntry.low_ino); +} + + +/* + Include Module support if requested. +*/ + +#ifdef MODULE + + +int init_module(void) +{ + int ControllerNumber, LogicalDriveNumber; + DAC960_Initialize(); + if (DAC960_ActiveControllerCount == 0) return -1; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) continue; + DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + } + return 0; +} + + +void cleanup_module(void) +{ + DAC960_Finalize(&DAC960_NotifierBlock, SYS_RESTART, NULL); +} + + +#endif diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h new file mode 100644 index 000000000..2ff757786 --- /dev/null +++ b/drivers/block/DAC960.h @@ -0,0 +1,2244 @@ +/* + + Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers + + Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com> + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + + The author respectfully requests that any modifications to this software be + sent directly to him for evaluation and testing. + +*/ + + +/* + Define the maximum number of DAC960 Controllers supported by this driver. +*/ + +#define DAC960_MaxControllers 8 + + +/* + Define the maximum number of Controller Channels supported by this driver. +*/ + +#define DAC960_MaxChannels 3 + + +/* + Define the maximum number of Targets per Channel supported by this driver. +*/ + +#define DAC960_MaxTargets 16 + + +/* + Define the maximum number of Logical Drives supported by any DAC960 model. +*/ + +#define DAC960_MaxLogicalDrives 32 + + +/* + Define a Boolean data type. +*/ + +typedef enum { false, true } __attribute__ ((packed)) boolean; + + +/* + Define a 32 bit I/O Address data type. +*/ + +typedef unsigned int DAC960_IO_Address_T; + + +/* + Define a 32 bit PCI Bus Address data type. +*/ + +typedef unsigned int DAC960_PCI_Address_T; + + +/* + Define a 32 bit Bus Address data type. +*/ + +typedef unsigned int DAC960_BusAddress_T; + + +/* + Define a 32 bit Byte Count data type. +*/ + +typedef unsigned int DAC960_ByteCount_T; + + +/* + Define the DAC960 Command Opcodes. +*/ + +typedef enum +{ + /* I/O Commands */ + DAC960_ReadExtended = 0x33, + DAC960_WriteExtended = 0x34, + DAC960_ReadAheadExtended = 0x35, + DAC960_ReadExtendedWithScatterGather = 0xB3, + DAC960_WriteExtendedWithScatterGather = 0xB4, + DAC960_Read = 0x36, + DAC960_ReadWithOldScatterGather = 0xB6, + DAC960_Write = 0x37, + DAC960_WriteWithOldScatterGather = 0xB7, + DAC960_DCDB = 0x04, + DAC960_DCDBWithScatterGather = 0x84, + DAC960_Flush = 0x0A, + /* Controller Status Related Commands */ + DAC960_Enquiry = 0x53, + DAC960_Enquiry2 = 0x1C, + DAC960_GetLogicalDriveElement = 0x55, + DAC960_GetLogicalDriveInformation = 0x19, + DAC960_IOPortRead = 0x39, + DAC960_IOPortWrite = 0x3A, + DAC960_GetSDStats = 0x3E, + DAC960_GetPDStats = 0x3F, + DAC960_PerformEventLogOperation = 0x72, + /* Device Related Commands */ + DAC960_StartDevice = 0x10, + DAC960_GetDeviceState = 0x50, + DAC960_StopChannel = 0x13, + DAC960_StartChannel = 0x12, + DAC960_ResetChannel = 0x1A, + /* Commands Associated with Data Consistency and Errors */ + DAC960_Rebuild = 0x09, + DAC960_RebuildAsync = 0x16, + DAC960_CheckConsistency = 0x0F, + DAC960_CheckConsistencyAsync = 0x1E, + DAC960_RebuildStat = 0x0C, + DAC960_GetRebuildProgress = 0x27, + DAC960_RebuildControl = 0x1F, + DAC960_ReadBadBlockTable = 0x0B, + DAC960_ReadBadDataTable = 0x25, + DAC960_ClearBadDataTable = 0x26, + DAC960_GetErrorTable = 0x17, + DAC960_AddCapacityAsync = 0x2A, + /* Configuration Related Commands */ + DAC960_ReadConfig2 = 0x3D, + DAC960_WriteConfig2 = 0x3C, + DAC960_ReadConfigurationOnDisk = 0x4A, + DAC960_WriteConfigurationOnDisk = 0x4B, + DAC960_ReadConfiguration = 0x4E, + DAC960_ReadBackupConfiguration = 0x4D, + DAC960_WriteConfiguration = 0x4F, + DAC960_AddConfiguration = 0x4C, + DAC960_ReadConfigurationLabel = 0x48, + DAC960_WriteConfigurationLabel = 0x49, + /* Firmware Upgrade Related Commands */ + DAC960_LoadImage = 0x20, + DAC960_StoreImage = 0x21, + DAC960_ProgramImage = 0x22, + /* Diagnostic Commands */ + DAC960_SetDiagnosticMode = 0x31, + DAC960_RunDiagnostic = 0x32, + /* Subsystem Service Commands */ + DAC960_GetSubsystemData = 0x70, + DAC960_SetSubsystemParameters = 0x71 +} +__attribute__ ((packed)) +DAC960_CommandOpcode_T; + + +/* + Define the DAC960 Command Identifier type. +*/ + +typedef unsigned char DAC960_CommandIdentifier_T; + + +/* + Define the DAC960 Command Status Codes. +*/ + +#define DAC960_NormalCompletion 0x0000 /* Common */ +#define DAC960_CheckConditionReceived 0x0002 /* Common */ +#define DAC960_NoDeviceAtAddress 0x0102 /* Common */ +#define DAC960_InvalidDeviceAddress 0x0105 /* Common */ +#define DAC960_InvalidParameter 0x0105 /* Common */ +#define DAC960_IrrecoverableDataError 0x0001 /* I/O */ +#define DAC960_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */ +#define DAC960_AccessBeyondEndOfLogicalDrive 0x0105 /* I/O */ +#define DAC960_BadDataEncountered 0x010C /* I/O */ +#define DAC960_DeviceBusy 0x0008 /* DCDB */ +#define DAC960_DeviceNonresponsive 0x000E /* DCDB */ +#define DAC960_CommandTerminatedAbnormally 0x000F /* DCDB */ +#define DAC960_UnableToStartDevice 0x0002 /* Device */ +#define DAC960_InvalidChannelOrTargetOrModifier 0x0105 /* Device */ +#define DAC960_ChannelBusy 0x0106 /* Device */ +#define DAC960_ChannelNotStopped 0x0002 /* Device */ +#define DAC960_AttemptToRebuildOnlineDrive 0x0002 /* Consistency */ +#define DAC960_RebuildBadBlocksEncountered 0x0003 /* Consistency */ +#define DAC960_NewDiskFailedDuringRebuild 0x0004 /* Consistency */ +#define DAC960_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */ +#define DAC960_DependentDiskIsDead 0x0002 /* Consistency */ +#define DAC960_InconsistentBlocksFound 0x0003 /* Consistency */ +#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */ +#define DAC960_NoRebuildOrCheckInProgress 0x0105 /* Consistency */ +#define DAC960_RebuildInProgress_DataValid 0x0000 /* Consistency */ +#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */ +#define DAC960_RebuildFailed_BadBlocksOnOther 0x0003 /* Consistency */ +#define DAC960_RebuildFailed_NewDriveFailed 0x0004 /* Consistency */ +#define DAC960_RebuildSuccessful 0x0100 /* Consistency */ +#define DAC960_AddCapacityInProgress 0x0004 /* Consistency */ +#define DAC960_AddCapacityFailedOrSuspended 0x00F4 /* Consistency */ +#define DAC960_Config2ChecksumError 0x0002 /* Configuration */ +#define DAC960_ConfigurationSuspended 0x0106 /* Configuration */ +#define DAC960_FailedToConfigureNVRAM 0x0105 /* Configuration */ +#define DAC960_ConfigurationNotSavedStateChange 0x0106 /* Configuration */ +#define DAC960_SubsystemNotInstalled 0x0001 /* Subsystem */ +#define DAC960_SubsystemFailed 0x0002 /* Subsystem */ +#define DAC960_SubsystemBusy 0x0106 /* Subsystem */ + +typedef unsigned short DAC960_CommandStatus_T; + + +/* + Define the Enquiry reply structure. +*/ + +typedef struct DAC960_Enquiry +{ + unsigned char NumberOfLogicalDrives; /* Byte 0 */ + unsigned int :24; /* Bytes 1-3 */ + unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */ + unsigned short FlashAge; /* Bytes 132-133 */ + struct { + boolean DeferredWriteError:1; /* Byte 134 Bit 0 */ + boolean BatteryLow:1; /* Byte 134 Bit 1 */ + unsigned char :6; /* Byte 134 Bits 2-7 */ + } StatusFlags; + unsigned char :8; /* Byte 135 */ + unsigned char MinorFirmwareVersion; /* Byte 136 */ + unsigned char MajorFirmwareVersion; /* Byte 137 */ + enum { + DAC960_NoStandbyRebuildOrCheckInProgress = 0x00, + DAC960_StandbyRebuildInProgress = 0x01, + DAC960_BackgroundRebuildInProgress = 0x02, + DAC960_BackgroundCheckInProgress = 0x03, + DAC960_StandbyRebuildCompletedWithError = 0xFF, + DAC960_BackgroundRebuildOrCheckFailed_DriveFailed = 0xF0, + DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed = 0xF1, + DAC960_BackgroundRebuildOrCheckFailed_OtherCauses = 0xF2, + DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated = 0xF3 + } __attribute__ ((packed)) RebuildFlag; /* Byte 138 */ + unsigned char MaxCommands; /* Byte 139 */ + unsigned char OfflineLogicalDriveCount; /* Byte 140 */ + unsigned char :8; /* Byte 141 */ + unsigned short EventLogSequenceNumber; /* Bytes 142-143 */ + unsigned char CriticalLogicalDriveCount; /* Byte 144 */ + unsigned int :24; /* Bytes 145-147 */ + unsigned char DeadDriveCount; /* Byte 148 */ + unsigned char :8; /* Byte 149 */ + unsigned char RebuildCount; /* Byte 150 */ + struct { + unsigned char :3; /* Byte 151 Bits 0-2 */ + boolean BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */ + unsigned char :3; /* Byte 151 Bits 4-6 */ + unsigned char :1; /* Byte 151 Bit 7 */ + } MiscFlags; + struct { + unsigned char TargetID; + unsigned char Channel; + } DeadDrives[21]; /* Bytes 152-194 */ + unsigned char Reserved[62]; /* Bytes 195-255 */ +} +__attribute__ ((packed)) +DAC960_Enquiry_T; + + +/* + Define the Enquiry2 reply structure. +*/ + +typedef struct DAC960_Enquiry2 +{ + struct { + enum { + DAC960_P_PD_PU = 0x01, + DAC960_PL = 0x02, + DAC960_PG = 0x10, + DAC960_PJ = 0x11, + DAC960_PR = 0x12, + DAC960_PT = 0x13, + DAC960_PTL0 = 0x14, + DAC960_PRL = 0x15, + DAC960_PTL1 = 0x16, + DAC1164_P = 0x20 + } __attribute__ ((packed)) SubModel; /* Byte 0 */ + unsigned char ActualChannels; /* Byte 1 */ + enum { + DAC960_FiveChannelBoard = 0x01, + DAC960_ThreeChannelBoard = 0x02, + DAC960_TwoChannelBoard = 0x03, + DAC960_ThreeChannelASIC_DAC = 0x04 + } __attribute__ ((packed)) Model; /* Byte 2 */ + enum { + DAC960_EISA_Controller = 0x01, + DAC960_MicroChannel_Controller = 0x02, + DAC960_PCI_Controller = 0x03, + DAC960_SCSItoSCSI_Controller = 0x08 + } __attribute__ ((packed)) ProductFamily; /* Byte 3 */ + } HardwareID; /* Bytes 0-3 */ + /* MajorVersion.MinorVersion-FirmwareType-TurnID */ + struct { + unsigned char MajorVersion; /* Byte 4 */ + unsigned char MinorVersion; /* Byte 5 */ + unsigned char TurnID; /* Byte 6 */ + char FirmwareType; /* Byte 7 */ + } FirmwareID; /* Bytes 4-7 */ + unsigned char :8; /* Byte 8 */ + unsigned int :24; /* Bytes 9-11 */ + unsigned char ConfiguredChannels; /* Byte 12 */ + unsigned char ActualChannels; /* Byte 13 */ + unsigned char MaxTargets; /* Byte 14 */ + unsigned char MaxTags; /* Byte 15 */ + unsigned char MaxLogicalDrives; /* Byte 16 */ + unsigned char MaxArms; /* Byte 17 */ + unsigned char MaxSpans; /* Byte 18 */ + unsigned char :8; /* Byte 19 */ + unsigned int :32; /* Bytes 20-23 */ + unsigned int MemorySize; /* Bytes 24-27 */ + unsigned int CacheSize; /* Bytes 28-31 */ + unsigned int FlashMemorySize; /* Bytes 32-35 */ + unsigned int NonVolatileMemorySize; /* Bytes 36-39 */ + struct { + enum { + DAC960_DRAM = 0x00, + DAC960_EDO = 0x01, + DAC960_SDRAM = 0x02 + } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */ + enum { + DAC960_None = 0x00, + DAC960_Parity = 0x01, + DAC960_ECC = 0x02 + } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */ + boolean FastPageMode:1; /* Byte 40 Bit 6 */ + boolean LowPowerMemory:1; /* Byte 40 Bit 7 */ + unsigned char :8; /* Bytes 41 */ + } MemoryType; + unsigned short ClockSpeed; /* Bytes 42-43 */ + unsigned short MemorySpeed; /* Bytes 44-45 */ + unsigned short HardwareSpeed; /* Bytes 46-47 */ + unsigned int :32; /* Bytes 48-51 */ + unsigned int :32; /* Bytes 52-55 */ + unsigned char :8; /* Byte 56 */ + unsigned char :8; /* Byte 57 */ + unsigned short :16; /* Bytes 58-59 */ + unsigned short MaxCommands; /* Bytes 60-61 */ + unsigned short MaxScatterGatherEntries; /* Bytes 62-63 */ + unsigned short MaxDriveCommands; /* Bytes 64-65 */ + unsigned short MaxIODescriptors; /* Bytes 66-67 */ + unsigned short MaxCombinedSectors; /* Bytes 68-69 */ + unsigned char Latency; /* Byte 70 */ + unsigned char :8; /* Byte 71 */ + unsigned char SCSITimeout; /* Byte 72 */ + unsigned char :8; /* Byte 73 */ + unsigned short MinFreeLines; /* Bytes 74-75 */ + unsigned int :32; /* Bytes 76-79 */ + unsigned int :32; /* Bytes 80-83 */ + unsigned char RebuildRateConstant; /* Byte 84 */ + unsigned char :8; /* Byte 85 */ + unsigned char :8; /* Byte 86 */ + unsigned char :8; /* Byte 87 */ + unsigned int :32; /* Bytes 88-91 */ + unsigned int :32; /* Bytes 92-95 */ + unsigned short PhysicalDriveBlockSize; /* Bytes 96-97 */ + unsigned short LogicalDriveBlockSize; /* Bytes 98-99 */ + unsigned short MaxBlocksPerCommand; /* Bytes 100-101 */ + unsigned short BlockFactor; /* Bytes 102-103 */ + unsigned short CacheLineSize; /* Bytes 104-105 */ + struct { + enum { + DAC960_Narrow_8bit = 0x00, + DAC960_Wide_16bit = 0x01, + DAC960_Wide_32bit = 0x02 + } __attribute__ ((packed)) BusWidth:2; /* Byte 106 Bits 0-1 */ + enum { + DAC960_Fast = 0x00, + DAC960_Ultra = 0x01, + DAC960_Ultra2 = 0x02 + } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */ + boolean Differential:1; /* Byte 106 Bit 4 */ + unsigned char :3; /* Byte 106 Bits 5-7 */ + } SCSICapability; + unsigned char :8; /* Byte 107 */ + unsigned int :32; /* Bytes 108-111 */ + unsigned short FirmwareBuildNumber; /* Bytes 112-113 */ + enum { + DAC960_AEMI = 0x01, + DAC960_OEM1 = 0x02, + DAC960_OEM2 = 0x04, + DAC960_OEM3 = 0x08, + DAC960_Conner = 0x10, + DAC960_SAFTE = 0x20 + } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */ + unsigned char :8; /* Byte 115 */ + struct { + boolean Clustering:1; /* Byte 116 Bit 0 */ + boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */ + unsigned int :30; /* Bytes 116-119 */ + } FirmwareFeatures; + unsigned int :32; /* Bytes 120-123 */ + unsigned int :32; /* Bytes 124-127 */ +} +DAC960_Enquiry2_T; + + +/* + Define the Logical Drive State type. +*/ + +typedef enum +{ + DAC960_LogicalDrive_Online = 0x03, + DAC960_LogicalDrive_Critical = 0x04, + DAC960_LogicalDrive_Offline = 0xFF +} +__attribute__ ((packed)) +DAC960_LogicalDriveState_T; + + +/* + Define the Get Logical Drive Information reply structure. +*/ + +typedef struct DAC960_LogicalDriveInformation +{ + unsigned int LogicalDriveSize; /* Bytes 0-3 */ + DAC960_LogicalDriveState_T LogicalDriveState; /* Byte 4 */ + unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */ + boolean WriteBack:1; /* Byte 5 Bit 7 */ + unsigned int :16; /* Bytes 6-7 */ +} +DAC960_LogicalDriveInformation_T; + + +/* + Define the Perform Event Log Operation Types. +*/ + +typedef enum +{ + DAC960_GetEventLogEntry = 0x00 +} +__attribute__ ((packed)) +DAC960_PerformEventLogOpType_T; + + +/* + Define the Get Event Log Entry reply structure. +*/ + +typedef struct DAC960_EventLogEntry +{ + unsigned char MessageType; /* Byte 0 */ + unsigned char MessageLength; /* Byte 1 */ + unsigned char TargetID:5; /* Byte 2 Bits 0-4 */ + unsigned char Channel:3; /* Byte 2 Bits 5-7 */ + unsigned char LogicalUnit:6; /* Byte 3 Bits 0-5 */ + unsigned char :2; /* Byte 3 Bits 6-7 */ + unsigned short SequenceNumber; /* Bytes 4-5 */ + unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */ + boolean Valid:1; /* Byte 6 Bit 7 */ + unsigned char SegmentNumber; /* Byte 7 */ + unsigned char SenseKey:4; /* Byte 8 Bits 0-3 */ + unsigned char :1; /* Byte 8 Bit 4 */ + boolean ILI:1; /* Byte 8 Bit 5 */ + boolean EOM:1; /* Byte 8 Bit 6 */ + boolean Filemark:1; /* Byte 8 Bit 7 */ + unsigned char Information[4]; /* Bytes 9-12 */ + unsigned char AdditionalSenseLength; /* Byte 13 */ + unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */ + unsigned char AdditionalSenseCode; /* Byte 18 */ + unsigned char AdditionalSenseCodeQualifier; /* Byte 19 */ + unsigned char Dummy[12]; /* Bytes 20-31 */ +} +DAC960_EventLogEntry_T; + + +/* + Define the Physical Device State type. +*/ + +typedef enum +{ + DAC960_Device_Dead = 0x00, + DAC960_Device_WriteOnly = 0x02, + DAC960_Device_Online = 0x03, + DAC960_Device_Standby = 0x10 +} +__attribute__ ((packed)) +DAC960_PhysicalDeviceState_T; + + +/* + Define the Get Device State reply structure. +*/ + +typedef struct DAC960_DeviceState +{ + boolean Present:1; /* Byte 0 Bit 0 */ + unsigned char :7; /* Byte 0 Bits 1-7 */ + enum { + DAC960_OtherType = 0x00, + DAC960_DiskType = 0x01, + DAC960_SequentialType = 0x02, + DAC960_CDROM_or_WORM_Type = 0x03 + } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */ + boolean :1; /* Byte 1 Bit 2 */ + boolean Fast20:1; /* Byte 1 Bit 3 */ + boolean Sync:1; /* Byte 1 Bit 4 */ + boolean Fast:1; /* Byte 1 Bit 5 */ + boolean Wide:1; /* Byte 1 Bit 6 */ + boolean TaggedQueuingSupported:1; /* Byte 1 Bit 7 */ + DAC960_PhysicalDeviceState_T DeviceState; /* Byte 2 */ + unsigned char :8; /* Byte 3 */ + unsigned char SynchronousMultiplier; /* Byte 4 */ + unsigned char SynchronousOffset:5; /* Byte 5 Bits 0-4 */ + unsigned char :3; /* Byte 5 Bits 5-7 */ + unsigned long DiskSize __attribute__ ((packed)); /* Bytes 6-9 */ +} +DAC960_DeviceState_T; + + +/* + Define the Get Rebuild Progress reply structure. +*/ + +typedef struct DAC960_RebuildProgress +{ + unsigned int LogicalDriveNumber; /* Bytes 0-3 */ + unsigned int LogicalDriveSize; /* Bytes 4-7 */ + unsigned int RemainingBlocks; /* Bytes 8-11 */ +} +DAC960_RebuildProgress_T; + + +/* + Define the Error Table Entry and Get Error Table reply structure. +*/ + +typedef struct DAC960_ErrorTableEntry +{ + unsigned char ParityErrorCount; /* Byte 0 */ + unsigned char SoftErrorCount; /* Byte 1 */ + unsigned char HardErrorCount; /* Byte 2 */ + unsigned char MiscErrorCount; /* Byte 3 */ +} +DAC960_ErrorTableEntry_T; + + +/* + Define the Get Error Table reply structure. +*/ + +typedef struct DAC960_ErrorTable +{ + DAC960_ErrorTableEntry_T + ErrorTableEntries[DAC960_MaxChannels][DAC960_MaxTargets]; +} +DAC960_ErrorTable_T; + + +/* + Define the Config2 reply structure. +*/ + +typedef struct DAC960_Config2 +{ + unsigned char :1; /* Byte 0 Bit 0 */ + boolean ActiveNegationEnabled:1; /* Byte 0 Bit 1 */ + unsigned char :5; /* Byte 0 Bits 2-6 */ + boolean NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */ + boolean StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */ + boolean HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */ + boolean NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */ + unsigned char :2; /* Byte 1 Bits 3-4 */ + boolean AEMI_ARM:1; /* Byte 1 Bit 5 */ + boolean AEMI_OFM:1; /* Byte 1 Bit 6 */ + unsigned char :1; /* Byte 1 Bit 7 */ + enum { + DAC960_OEMID_Mylex = 0x00, + DAC960_OEMID_IBM = 0x08, + DAC960_OEMID_HP = 0x0A, + DAC960_OEMID_DEC = 0x0C, + DAC960_OEMID_Siemens = 0x10, + DAC960_OEMID_Intel = 0x12 + } __attribute__ ((packed)) OEMID; /* Byte 2 */ + unsigned char OEMModelNumber; /* Byte 3 */ + unsigned char PhysicalSector; /* Byte 4 */ + unsigned char LogicalSector; /* Byte 5 */ + unsigned char BlockFactor; /* Byte 6 */ + boolean ReadAheadEnabled:1; /* Byte 7 Bit 0 */ + boolean LowBIOSDelay:1; /* Byte 7 Bit 1 */ + unsigned char :2; /* Byte 7 Bits 2-3 */ + boolean ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */ + unsigned char :1; /* Byte 7 Bit 5 */ + boolean ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */ + boolean EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */ + unsigned char DefaultRebuildRate; /* Byte 8 */ + unsigned char :8; /* Byte 9 */ + unsigned char BlocksPerCacheLine; /* Byte 10 */ + unsigned char BlocksPerStripe; /* Byte 11 */ + struct { + enum { + DAC960_Async = 0x00, + DAC960_Sync_8MHz = 0x01, + DAC960_Sync_5MHz = 0x02, + DAC960_Sync_10or20MHz = 0x03 /* Bits 0-1 */ + } __attribute__ ((packed)) Speed:2; + boolean Force8Bit:1; /* Bit 2 */ + boolean DisableFast20:1; /* Bit 3 */ + unsigned char :3; /* Bits 4-6 */ + boolean EnableTaggedQueuing:1; /* Bit 7 */ + } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */ + unsigned char SCSIInitiatorID; /* Byte 18 */ + unsigned char :8; /* Byte 19 */ + enum { + DAC960_StartupMode_ControllerSpinUp = 0x00, + DAC960_StartupMode_PowerOnSpinUp = 0x01 + } __attribute__ ((packed)) StartupMode; /* Byte 20 */ + unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */ + unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */ + unsigned char Reserved1[29]; /* Bytes 23-51 */ + boolean BIOSDisabled:1; /* Byte 52 Bit 0 */ + boolean CDROMBootEnabled:1; /* Byte 52 Bit 1 */ + unsigned char :3; /* Byte 52 Bits 2-4 */ + enum { + DAC960_Geometry_128_32 = 0x00, + DAC960_Geometry_255_63 = 0x01, + DAC960_Geometry_Reserved1 = 0x02, + DAC960_Geometry_Reserved2 = 0x03 + } __attribute__ ((packed)) DriveGeometry:2; /* Byte 52 Bits 5-6 */ + unsigned char :1; /* Byte 52 Bit 7 */ + unsigned char Reserved2[9]; /* Bytes 53-61 */ + unsigned short Checksum; /* Bytes 62-63 */ +} +DAC960_Config2_T; + + +/* + Define the DCDB request structure. +*/ + +typedef struct DAC960_DCDB +{ + unsigned char TargetID:4; /* Byte 0 Bits 0-3 */ + unsigned char Channel:4; /* Byte 0 Bits 4-7 */ + enum { + DAC960_DCDB_NoDataTransfer = 0, + DAC960_DCDB_DataTransferDeviceToSystem = 1, + DAC960_DCDB_DataTransferSystemToDevice = 2, + DAC960_DCDB_IllegalDataTransfer = 3 + } __attribute__ ((packed)) Direction:2; /* Byte 1 Bits 0-1 */ + boolean EarlyStatus:1; /* Byte 1 Bit 2 */ + unsigned char :1; /* Byte 1 Bit 3 */ + enum { + DAC960_DCDB_Timeout_24_hours = 0, + DAC960_DCDB_Timeout_10_seconds = 1, + DAC960_DCDB_Timeout_60_seconds = 2, + DAC960_DCDB_Timeout_10_minutes = 3 + } __attribute__ ((packed)) Timeout:2; /* Byte 1 Bits 4-5 */ + boolean NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */ + boolean DisconnectPermitted:1; /* Byte 1 Bit 7 */ + unsigned short TransferLength; /* Bytes 2-3 */ + DAC960_BusAddress_T BusAddress; /* Bytes 4-7 */ + unsigned char CDBLength:4; /* Byte 8 Bits 0-3 */ + unsigned char TransferLengthHigh4:4; /* Byte 8 Bits 4-7 */ + unsigned char SenseLength; /* Byte 9 */ + unsigned char CDB[12]; /* Bytes 10-21 */ + unsigned char SenseData[64]; /* Bytes 22-85 */ + unsigned char Status; /* Byte 86 */ + unsigned char :8; /* Byte 87 */ +} +DAC960_DCDB_T; + + +/* + Define the SCSI INQUIRY Standard Data reply structure. +*/ + +typedef struct DAC960_SCSI_Inquiry +{ + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ + unsigned char :2; /* Byte 3 Bits 4-5 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + boolean AENC:1; /* Byte 3 Bit 7 */ + unsigned char AdditionalLength; /* Byte 4 */ + unsigned char :8; /* Byte 5 */ + unsigned char :8; /* Byte 6 */ + boolean SftRe:1; /* Byte 7 Bit 0 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean :1; /* Byte 7 Bit 2 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean RelAdr:1; /* Byte 7 Bit 7 */ + unsigned char VendorIdentification[8]; /* Bytes 8-15 */ + unsigned char ProductIdentification[16]; /* Bytes 16-31 */ + unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ +} +DAC960_SCSI_Inquiry_T; + + +/* + Define the SCSI INQUIRY Unit Serial Number reply structure. +*/ + +typedef struct DAC960_SCSI_Inquiry_UnitSerialNumber +{ + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char PageCode; /* Byte 1 */ + unsigned char :8; /* Byte 2 */ + unsigned char PageLength; /* Byte 3 */ + unsigned char ProductSerialNumber[28]; /* Bytes 4 - 31 */ +} +DAC960_SCSI_Inquiry_UnitSerialNumber_T; + + +/* + Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count + structure. +*/ + +typedef struct DAC960_ScatterGatherSegment +{ + DAC960_BusAddress_T SegmentDataPointer; /* Bytes 0-3 */ + DAC960_ByteCount_T SegmentByteCount; /* Bytes 4-7 */ +} +DAC960_ScatterGatherSegment_T; + + +/* + Define the 13 Byte DAC960 Command Mailbox structure. Bytes 13-15 are + not used. The Command Mailbox structure is padded to 16 bytes for + efficient access. +*/ + +typedef union DAC960_CommandMailbox +{ + unsigned int Words[4]; /* Words 0-3 */ + unsigned char Bytes[16]; /* Bytes 0-15 */ + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy[14]; /* Bytes 2-15 */ + } __attribute__ ((packed)) Common; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[6]; /* Bytes 2-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[5]; /* Bytes 2-6 */ + unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */ + boolean AutoRestore:1; /* Byte 7 Bit 7 */ + unsigned char Dummy2[8]; /* Bytes 8-15 */ + } __attribute__ ((packed)) Type3C; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Channel; /* Byte 2 */ + unsigned char TargetID; /* Byte 3 */ + DAC960_PhysicalDeviceState_T DeviceState:5; /* Byte 4 Bits 0-4 */ + unsigned char Modifier:3; /* Byte 4 Bits 5-7 */ + unsigned char Dummy1[3]; /* Bytes 5-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3D; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + DAC960_PerformEventLogOpType_T OperationType; /* Byte 2 */ + unsigned char OperationQualifier; /* Byte 3 */ + unsigned short SequenceNumber; /* Bytes 4-5 */ + unsigned char Dummy1[2]; /* Bytes 6-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3E; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[2]; /* Bytes 2-3 */ + unsigned char RebuildRateConstant; /* Byte 4 */ + unsigned char Dummy2[3]; /* Bytes 5-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy3[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3R; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned short TransferLength; /* Bytes 2-3 */ + unsigned int LogicalBlockAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char LogicalDriveNumber; /* Byte 12 */ + unsigned char Dummy[3]; /* Bytes 13-15 */ + } __attribute__ ((packed)) Type4; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + struct { + unsigned short TransferLength:11; /* Bytes 2-3 */ + unsigned char LogicalDriveNumber:5; /* Byte 3 Bits 3-7 */ + } __attribute__ ((packed)) LD; + unsigned int LogicalBlockAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char ScatterGatherCount:6; /* Byte 12 Bits 0-5 */ + enum { + DAC960_ScatterGather_32BitAddress_32BitByteCount = 0x0, + DAC960_ScatterGather_32BitAddress_16BitByteCount = 0x1, + DAC960_ScatterGather_32BitByteCount_32BitAddress = 0x2, + DAC960_ScatterGather_16BitByteCount_32BitAddress = 0x3 + } __attribute__ ((packed)) ScatterGatherType:2; /* Byte 12 Bits 6-7 */ + unsigned char Dummy[3]; /* Bytes 13-15 */ + } __attribute__ ((packed)) Type5; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char CommandOpcode2; /* Byte 2 */ + unsigned char :8; /* Byte 3 */ + DAC960_BusAddress_T CommandMailboxesBusAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T StatusMailboxesBusAddress; /* Bytes 8-11 */ + unsigned char Dummy[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) TypeX; +} +DAC960_CommandMailbox_T; + + +/* + Define the DAC960 Driver IOCTL requests. +*/ + +#define DAC960_IOCTL_GET_CONTROLLER_COUNT 0xDAC001 +#define DAC960_IOCTL_GET_CONTROLLER_INFO 0xDAC002 +#define DAC960_IOCTL_EXECUTE_COMMAND 0xDAC003 + + +/* + Define the DAC960_IOCTL_GET_CONTROLLER_INFO reply structure. +*/ + +typedef struct DAC960_ControllerInfo +{ + unsigned char ControllerNumber; + unsigned char PCI_Bus; + unsigned char PCI_Device; + unsigned char PCI_Function; + unsigned char IRQ_Channel; + unsigned char Channels; + DAC960_PCI_Address_T PCI_Address; + unsigned char ModelName[16]; + unsigned char FirmwareVersion[16]; +} +DAC960_ControllerInfo_T; + + +/* + Define the User Mode DAC960_IOCTL_EXECUTE_COMMAND request structure. +*/ + +typedef struct DAC960_UserCommand +{ + unsigned char ControllerNumber; + DAC960_CommandMailbox_T CommandMailbox; + int DataTransferLength; + void *DataTransferBuffer; + DAC960_DCDB_T *DCDB; +} +DAC960_UserCommand_T; + + +/* + Define the Kernel Mode DAC960_IOCTL_EXECUTE_COMMAND request structure. +*/ + +typedef struct DAC960_KernelCommand +{ + unsigned char ControllerNumber; + DAC960_CommandMailbox_T CommandMailbox; + int DataTransferLength; + void *DataTransferBuffer; + DAC960_DCDB_T *DCDB; + DAC960_CommandStatus_T CommandStatus; + void (*CompletionFunction)(struct DAC960_KernelCommand *); + void *CompletionData; +} +DAC960_KernelCommand_T; + + +/* + Import the Kernel Mode IOCTL interface. +*/ + +extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument); + + +/* + Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. +*/ + +static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress) +{ + return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress); +} + + +/* + Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. +*/ + +static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress) +{ + return (void *) bus_to_virt(BusAddress); +} + + +/* + DAC960_DriverVersion protects the private portion of this file. +*/ + +#ifdef DAC960_DriverVersion + + +/* + Define the maximum Driver Queue Depth and Controller Queue Depth supported + by any DAC960 model. +*/ + +#define DAC960_MaxDriverQueueDepth 127 +#define DAC960_MaxControllerQueueDepth 128 + + +/* + Define the maximum number of Scatter/Gather Segments supported by any + DAC960 model. +*/ + +#define DAC960_MaxScatterGatherSegments 33 + + +/* + Define the number of Command Mailboxes and Status Mailboxes used by the + Memory Mailbox Interface. +*/ + +#define DAC960_CommandMailboxCount 256 +#define DAC960_StatusMailboxCount 1024 + + +/* + Define the DAC960 Controller Monitoring Timer Interval. +*/ + +#define DAC960_MonitoringTimerInterval (10 * HZ) + + +/* + Define the DAC960 Controller Secondary Monitoring Interval. +*/ + +#define DAC960_SecondaryMonitoringInterval (60 * HZ) + + +/* + Define the DAC960 Controller Progress Reporting Interval. +*/ + +#define DAC960_ProgressReportingInterval (60 * HZ) + + +/* + Define the maximum number of Partitions allowed for each Logical Drive. +*/ + +#define DAC960_MaxPartitions 8 +#define DAC960_MaxPartitionsBits 3 + + +/* + Define macros to extract the Controller Number, Logical Drive Number, and + Partition Number from a Kernel Device, and to construct a Major Number, Minor + Number, and Kernel Device from the Controller Number, Logical Drive Number, + and Partition Number. There is one Major Number assigned to each Controller. + The associated Minor Number is divided into the Logical Drive Number and + Partition Number. +*/ + +#define DAC960_ControllerNumber(Device) \ + (MAJOR(Device) - DAC960_MAJOR) + +#define DAC960_LogicalDriveNumber(Device) \ + (MINOR(Device) >> DAC960_MaxPartitionsBits) + +#define DAC960_PartitionNumber(Device) \ + (MINOR(Device) & (DAC960_MaxPartitions - 1)) + +#define DAC960_MajorNumber(ControllerNumber) \ + (DAC960_MAJOR + (ControllerNumber)) + +#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \ + (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber)) + +#define DAC960_MinorCount (DAC960_MaxLogicalDrives \ + * DAC960_MaxPartitions) + +#define DAC960_KernelDevice(ControllerNumber, \ + LogicalDriveNumber, \ + PartitionNumber) \ + MKDEV(DAC960_MajorNumber(ControllerNumber), \ + DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber)) + + +/* + Define the DAC960 Controller fixed Block Size and Block Size Bits. +*/ + +#define DAC960_BlockSize 512 +#define DAC960_BlockSizeBits 9 + + +/* + Define the Controller Line Buffer, Status Buffer, Rebuild Progress, + and User Message Sizes. +*/ + +#define DAC960_LineBufferSize 100 +#define DAC960_StatusBufferSize 16384 +#define DAC960_RebuildProgressSize 200 +#define DAC960_UserMessageSize 200 + + +/* + Define the types of DAC960 Controllers that are supported. +*/ + +typedef enum +{ + DAC960_V5_Controller = 1, /* DAC1164P */ + DAC960_V4_Controller = 2, /* DAC960PTL/PJ/PG */ + DAC960_V3_Controller = 3 /* DAC960PU/PD/PL */ +} +DAC960_ControllerType_T; + + +/* + Define the Driver Message Levels. +*/ + +typedef enum DAC960_MessageLevel +{ + DAC960_AnnounceLevel = 0, + DAC960_InfoLevel = 1, + DAC960_NoticeLevel = 2, + DAC960_WarningLevel = 3, + DAC960_ErrorLevel = 4, + DAC960_ProgressLevel = 5, + DAC960_CriticalLevel = 6, + DAC960_UserCriticalLevel = 7 +} +DAC960_MessageLevel_T; + +static char + *DAC960_MessageLevelMap[] = + { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, + KERN_ERR, KERN_CRIT, KERN_CRIT, KERN_CRIT }; + + +/* + Define Driver Message macros. +*/ + +#define DAC960_Announce(Format, Arguments...) \ + DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments) + +#define DAC960_Info(Format, Arguments...) \ + DAC960_Message(DAC960_InfoLevel, Format, ##Arguments) + +#define DAC960_Notice(Format, Arguments...) \ + DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments) + +#define DAC960_Warning(Format, Arguments...) \ + DAC960_Message(DAC960_WarningLevel, Format, ##Arguments) + +#define DAC960_Error(Format, Arguments...) \ + DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments) + +#define DAC960_Progress(Format, Arguments...) \ + DAC960_Message(DAC960_ProgressLevel, Format, ##Arguments) + +#define DAC960_Critical(Format, Arguments...) \ + DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments) + +#define DAC960_UserCritical(Format, Arguments...) \ + DAC960_Message(DAC960_UserCriticalLevel, Format, ##Arguments) + + +/* + Define types for some of the structures that interface with the rest + of the Linux Kernel and I/O Subsystem. +*/ + +typedef struct buffer_head BufferHeader_T; +typedef struct file File_T; +typedef struct file_operations FileOperations_T; +typedef struct gendisk GenericDiskInfo_T; +typedef struct hd_geometry DiskGeometry_T; +typedef struct hd_struct DiskPartition_T; +typedef struct inode Inode_T; +typedef struct inode_operations InodeOperations_T; +typedef kdev_t KernelDevice_T; +typedef struct notifier_block NotifierBlock_T; +typedef struct pci_dev PCI_Device_T; +typedef struct proc_dir_entry PROC_DirectoryEntry_T; +typedef unsigned long ProcessorFlags_T; +typedef struct pt_regs Registers_T; +typedef struct request IO_Request_T; +typedef struct semaphore Semaphore_T; +typedef struct super_block SuperBlock_T; +typedef struct timer_list Timer_T; +typedef wait_queue_head_t WaitQueue_T; + + +/* + Define the DAC960 Controller Status Mailbox structure. +*/ + +typedef union DAC960_StatusMailbox +{ + unsigned int Word; /* Bytes 0-3 */ + struct { + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 0 */ + unsigned char :7; /* Byte 1 Bits 0-6 */ + boolean Valid:1; /* Byte 1 Bit 7 */ + DAC960_CommandStatus_T CommandStatus; /* Bytes 2-3 */ + } Fields; +} +DAC960_StatusMailbox_T; + + +/* + Define the DAC960 Driver Command Types. +*/ + +typedef enum +{ + DAC960_ReadCommand = 1, + DAC960_WriteCommand = 2, + DAC960_ReadRetryCommand = 3, + DAC960_WriteRetryCommand = 4, + DAC960_MonitoringCommand = 5, + DAC960_ImmediateCommand = 6, + DAC960_QueuedCommand = 7 +} +DAC960_CommandType_T; + + +/* + Define the DAC960 Driver Command structure. +*/ + +typedef struct DAC960_Command +{ + DAC960_CommandType_T CommandType; + DAC960_CommandMailbox_T CommandMailbox; + DAC960_CommandStatus_T CommandStatus; + struct DAC960_Controller *Controller; + struct DAC960_Command *Next; + Semaphore_T *Semaphore; + unsigned int LogicalDriveNumber; + unsigned int BlockNumber; + unsigned int BlockCount; + unsigned int SegmentCount; + BufferHeader_T *BufferHeader; + DAC960_KernelCommand_T *KernelCommand; + DAC960_ScatterGatherSegment_T + ScatterGatherList[DAC960_MaxScatterGatherSegments]; +} +DAC960_Command_T; + + +/* + Define the DAC960 Driver Controller structure. +*/ + +typedef struct DAC960_Controller +{ + void *BaseAddress; + void *MemoryMappedAddress; + DAC960_ControllerType_T ControllerType; + DAC960_IO_Address_T IO_Address; + DAC960_PCI_Address_T PCI_Address; + unsigned char ControllerNumber; + unsigned char ControllerName[4]; + unsigned char ModelName[12]; + unsigned char FullModelName[18]; + unsigned char FirmwareVersion[14]; + unsigned char Bus; + unsigned char Device; + unsigned char Function; + unsigned char IRQ_Channel; + unsigned char Channels; + unsigned char MemorySize; + unsigned char LogicalDriveCount; + unsigned char GeometryTranslationHeads; + unsigned char GeometryTranslationSectors; + unsigned short ControllerQueueDepth; + unsigned short DriverQueueDepth; + unsigned short MaxBlocksPerCommand; + unsigned short MaxScatterGatherSegments; + unsigned short StripeSize; + unsigned short SegmentSize; + unsigned short NewEventLogSequenceNumber; + unsigned short OldEventLogSequenceNumber; + unsigned short InitialStatusLength; + unsigned short CurrentStatusLength; + unsigned short UserStatusLength; + unsigned short RebuildProgressLength; + unsigned int ControllerUsageCount; + unsigned int EnquiryIndex; + unsigned int LogicalDriveInformationIndex; + unsigned int ErrorTableIndex; + unsigned int DeviceStateIndex; + unsigned int DeviceStateChannel; + unsigned int DeviceStateTargetID; + unsigned long MonitoringTimerCount; + unsigned long SecondaryMonitoringTime; + unsigned long LastProgressReportTime; + unsigned long LastCurrentStatusTime; + boolean DualModeMemoryMailboxInterface; + boolean SAFTE_EnclosureManagementEnabled; + boolean ControllerInitialized; + boolean MonitoringCommandDeferred; + boolean NeedLogicalDriveInformation; + boolean NeedErrorTableInformation; + boolean NeedDeviceStateInformation; + boolean NeedDeviceInquiryInformation; + boolean NeedDeviceSerialNumberInformation; + boolean NeedRebuildProgress; + boolean NeedConsistencyCheckProgress; + boolean EphemeralProgressMessage; + Timer_T MonitoringTimer; + GenericDiskInfo_T GenericDiskInfo; + DAC960_Command_T *FreeCommands; + DAC960_CommandMailbox_T *FirstCommandMailbox; + DAC960_CommandMailbox_T *LastCommandMailbox; + DAC960_CommandMailbox_T *NextCommandMailbox; + DAC960_CommandMailbox_T *PreviousCommandMailbox1; + DAC960_CommandMailbox_T *PreviousCommandMailbox2; + DAC960_StatusMailbox_T *FirstStatusMailbox; + DAC960_StatusMailbox_T *LastStatusMailbox; + DAC960_StatusMailbox_T *NextStatusMailbox; + PROC_DirectoryEntry_T ControllerProcEntry; + PROC_DirectoryEntry_T InitialStatusProcEntry; + PROC_DirectoryEntry_T CurrentStatusProcEntry; + PROC_DirectoryEntry_T UserCommandProcEntry; + WaitQueue_T CommandWaitQueue; + DAC960_DCDB_T MonitoringDCDB; + DAC960_Enquiry_T Enquiry[2]; + DAC960_ErrorTable_T ErrorTable[2]; + DAC960_EventLogEntry_T EventLogEntry; + DAC960_RebuildProgress_T RebuildProgress; + DAC960_CommandStatus_T LastRebuildStatus; + DAC960_LogicalDriveInformation_T + LogicalDriveInformation[2][DAC960_MaxLogicalDrives]; + DAC960_LogicalDriveState_T LogicalDriveInitialState[DAC960_MaxLogicalDrives]; + DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets]; + DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth]; + DAC960_SCSI_Inquiry_T + InquiryStandardData[DAC960_MaxChannels][DAC960_MaxTargets]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T + InquiryUnitSerialNumber[DAC960_MaxChannels][DAC960_MaxTargets]; + DiskPartition_T DiskPartitions[DAC960_MinorCount]; + int LogicalDriveUsageCount[DAC960_MaxLogicalDrives]; + int PartitionSizes[DAC960_MinorCount]; + int BlockSizes[DAC960_MinorCount]; + int MaxSectorsPerRequest[DAC960_MinorCount]; + int MaxSegmentsPerRequest[DAC960_MinorCount]; + int DeviceResetCount[DAC960_MaxChannels][DAC960_MaxTargets]; + boolean DirectCommandActive[DAC960_MaxChannels][DAC960_MaxTargets]; + char InitialStatusBuffer[DAC960_StatusBufferSize]; + char CurrentStatusBuffer[DAC960_StatusBufferSize]; + char UserStatusBuffer[DAC960_UserMessageSize]; + char RebuildProgressBuffer[DAC960_RebuildProgressSize]; +} +DAC960_Controller_T; + + +/* + DAC960_AcquireControllerLock acquires exclusive access to Controller. +*/ + +static inline +void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_lock_irqsave(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_ReleaseControllerLock releases exclusive access to Controller. +*/ + +static inline +void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_AcquireControllerLockRF acquires exclusive access to Controller, + but is only called from the request function with the io_request_lock held. +*/ + +static inline +void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ +} + + +/* + DAC960_ReleaseControllerLockRF releases exclusive access to Controller, + but is only called from the request function with the io_request_lock held. +*/ + +static inline +void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ +} + + +/* + DAC960_AcquireControllerLockIH acquires exclusive access to Controller, + but is only called from the interrupt handler. +*/ + +static inline +void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_lock_irqsave(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_ReleaseControllerLockIH releases exclusive access to Controller, + but is only called from the interrupt handler. +*/ + +static inline +void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); +} + + +/* + Define the DAC960 V5 Controller Interface Register Offsets. +*/ + +#define DAC960_V5_RegisterWindowSize 0x80 + +typedef enum +{ + DAC960_V5_InboundDoorBellRegisterOffset = 0x60, + DAC960_V5_OutboundDoorBellRegisterOffset = 0x61, + DAC960_V5_InterruptMaskRegisterOffset = 0x34, + DAC960_V5_CommandOpcodeRegisterOffset = 0x50, + DAC960_V5_CommandIdentifierRegisterOffset = 0x51, + DAC960_V5_MailboxRegister2Offset = 0x52, + DAC960_V5_MailboxRegister3Offset = 0x53, + DAC960_V5_MailboxRegister4Offset = 0x54, + DAC960_V5_MailboxRegister5Offset = 0x55, + DAC960_V5_MailboxRegister6Offset = 0x56, + DAC960_V5_MailboxRegister7Offset = 0x57, + DAC960_V5_MailboxRegister8Offset = 0x58, + DAC960_V5_MailboxRegister9Offset = 0x59, + DAC960_V5_MailboxRegister10Offset = 0x5A, + DAC960_V5_MailboxRegister11Offset = 0x5B, + DAC960_V5_MailboxRegister12Offset = 0x5C, + DAC960_V5_StatusCommandIdentifierRegOffset = 0x5D, + DAC960_V5_StatusRegisterOffset = 0x5E +} +DAC960_V5_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V5 Inbound Door Bell Register. +*/ + +typedef union DAC960_V5_InboundDoorBellRegister +{ + unsigned char All; + struct { + boolean HardwareMailboxNewCommand:1; /* Bit 0 */ + boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + unsigned char :3; /* Bits 5-7 */ + } Write; + struct { + boolean HardwareMailboxEmpty:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V5_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V5 Outbound Door Bell Register. +*/ + +typedef union DAC960_V5_OutboundDoorBellRegister +{ + unsigned char All; + struct { + boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + unsigned char :6; /* Bits 2-7 */ + } Write; + struct { + boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ + boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + unsigned char :6; /* Bits 2-7 */ + } Read; +} +DAC960_V5_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V5 Interrupt Mask Register. +*/ + +typedef union DAC960_V5_InterruptMaskRegister +{ + unsigned char All; + struct { + unsigned char :2; /* Bits 0-1 */ + boolean DisableInterrupts:1; /* Bit 2 */ + unsigned char :5; /* Bits 3-7 */ + } Bits; +} +DAC960_V5_InterruptMaskRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V5 Controller Interface Registers. +*/ + +static inline +void DAC960_V5_HardwareMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_MemoryMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V5_HardwareMailboxEmptyP(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.HardwareMailboxEmpty; +} + +static inline +void DAC960_V5_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V5_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; +} + +static inline +boolean DAC960_V5_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; +} + +static inline +void DAC960_V5_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.DisableInterrupts = false; + writeb(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); +} + +static inline +void DAC960_V5_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.DisableInterrupts = true; + writeb(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); +} + +static inline +boolean DAC960_V5_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = + readb(ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); + return !InterruptMaskRegister.Bits.DisableInterrupts; +} + +static inline +void DAC960_V5_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox, + DAC960_CommandMailbox_T *CommandMailbox) +{ + NextCommandMailbox->Words[1] = CommandMailbox->Words[1]; + NextCommandMailbox->Words[2] = CommandMailbox->Words[2]; + NextCommandMailbox->Words[3] = CommandMailbox->Words[3]; + NextCommandMailbox->Words[0] = CommandMailbox->Words[0]; +} + +static inline +void DAC960_V5_WriteHardwareMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V5_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V5_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V5_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V5_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V5_StatusRegisterOffset); +} + +static inline +void DAC960_V5_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + writel(0x743C485E, + ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset); + writel((unsigned long) Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset); +} + +static inline +void DAC960_V5_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, + void **MemoryMailboxAddress, + short *NextCommandMailboxIndex, + short *NextStatusMailboxIndex) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + if (readl(ControllerBaseAddress + + DAC960_V5_CommandOpcodeRegisterOffset) != 0x743C485E) + return; + *MemoryMailboxAddress = + (void *) readl(ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + *NextCommandMailboxIndex = + readw(ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + *NextStatusMailboxIndex = + readw(ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset); +} + + +/* + Define the DAC960 V4 Controller Interface Register Offsets. +*/ + +#define DAC960_V4_RegisterWindowSize 0x2000 + +typedef enum +{ + DAC960_V4_InboundDoorBellRegisterOffset = 0x0020, + DAC960_V4_OutboundDoorBellRegisterOffset = 0x002C, + DAC960_V4_InterruptMaskRegisterOffset = 0x0034, + DAC960_V4_CommandOpcodeRegisterOffset = 0x1000, + DAC960_V4_CommandIdentifierRegisterOffset = 0x1001, + DAC960_V4_MailboxRegister2Offset = 0x1002, + DAC960_V4_MailboxRegister3Offset = 0x1003, + DAC960_V4_MailboxRegister4Offset = 0x1004, + DAC960_V4_MailboxRegister5Offset = 0x1005, + DAC960_V4_MailboxRegister6Offset = 0x1006, + DAC960_V4_MailboxRegister7Offset = 0x1007, + DAC960_V4_MailboxRegister8Offset = 0x1008, + DAC960_V4_MailboxRegister9Offset = 0x1009, + DAC960_V4_MailboxRegister10Offset = 0x100A, + DAC960_V4_MailboxRegister11Offset = 0x100B, + DAC960_V4_MailboxRegister12Offset = 0x100C, + DAC960_V4_StatusCommandIdentifierRegOffset = 0x1018, + DAC960_V4_StatusRegisterOffset = 0x101A +} +DAC960_V4_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V4 Inbound Door Bell Register. +*/ + +typedef union DAC960_V4_InboundDoorBellRegister +{ + unsigned int All; + struct { + boolean HardwareMailboxNewCommand:1; /* Bit 0 */ + boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + unsigned int :27; /* Bits 5-31 */ + } Write; + struct { + boolean HardwareMailboxFull:1; /* Bit 0 */ + unsigned int :31; /* Bits 1-31 */ + } Read; +} +DAC960_V4_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V4 Outbound Door Bell Register. +*/ + +typedef union DAC960_V4_OutboundDoorBellRegister +{ + unsigned int All; + struct { + boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + unsigned int :30; /* Bits 2-31 */ + } Write; + struct { + boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ + boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + unsigned int :30; /* Bits 2-31 */ + } Read; +} +DAC960_V4_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V4 Interrupt Mask Register. +*/ + +typedef union DAC960_V4_InterruptMaskRegister +{ + unsigned int All; + struct { + unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */ + boolean DisableInterrupts:1; /* Bit 2 */ + unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */ + unsigned int Reserved0:24; /* Bits 8-31 */ + } Bits; +} +DAC960_V4_InterruptMaskRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V4 Controller Interface Registers. +*/ + +static inline +void DAC960_V4_HardwareMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_MemoryMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V4_HardwareMailboxFullP(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.HardwareMailboxFull; +} + +static inline +void DAC960_V4_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V4_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; +} + +static inline +boolean DAC960_V4_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; +} + +static inline +void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; + InterruptMaskRegister.Bits.DisableInterrupts = false; + InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; + writel(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); +} + +static inline +void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; + InterruptMaskRegister.Bits.DisableInterrupts = true; + InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; + writel(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); +} + +static inline +boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = + readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); + return !InterruptMaskRegister.Bits.DisableInterrupts; +} + +static inline +void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox, + DAC960_CommandMailbox_T *CommandMailbox) +{ + NextCommandMailbox->Words[1] = CommandMailbox->Words[1]; + NextCommandMailbox->Words[2] = CommandMailbox->Words[2]; + NextCommandMailbox->Words[3] = CommandMailbox->Words[3]; + NextCommandMailbox->Words[0] = CommandMailbox->Words[0]; +} + +static inline +void DAC960_V4_WriteHardwareMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V4_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset); +} + +static inline +void DAC960_V4_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + writel(0xAABBFFFF, + ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset); + writel((unsigned long) Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset); +} + +static inline +void DAC960_V4_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, + void **MemoryMailboxAddress, + short *NextCommandMailboxIndex, + short *NextStatusMailboxIndex) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + if (readl(ControllerBaseAddress + + DAC960_V4_CommandOpcodeRegisterOffset) != 0xAABBFFFF) + return; + *MemoryMailboxAddress = + (void *) readl(ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + *NextCommandMailboxIndex = + readw(ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + *NextStatusMailboxIndex = + readw(ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset); +} + + +/* + Define the DAC960 V3 Controller Interface Register Offsets. +*/ + +#define DAC960_V3_RegisterWindowSize 0x80 + +typedef enum +{ + DAC960_V3_CommandOpcodeRegisterOffset = 0x00, + DAC960_V3_CommandIdentifierRegisterOffset = 0x01, + DAC960_V3_MailboxRegister2Offset = 0x02, + DAC960_V3_MailboxRegister3Offset = 0x03, + DAC960_V3_MailboxRegister4Offset = 0x04, + DAC960_V3_MailboxRegister5Offset = 0x05, + DAC960_V3_MailboxRegister6Offset = 0x06, + DAC960_V3_MailboxRegister7Offset = 0x07, + DAC960_V3_MailboxRegister8Offset = 0x08, + DAC960_V3_MailboxRegister9Offset = 0x09, + DAC960_V3_MailboxRegister10Offset = 0x0A, + DAC960_V3_MailboxRegister11Offset = 0x0B, + DAC960_V3_MailboxRegister12Offset = 0x0C, + DAC960_V3_StatusCommandIdentifierRegOffset = 0x0D, + DAC960_V3_StatusRegisterOffset = 0x0E, + DAC960_V3_InboundDoorBellRegisterOffset = 0x40, + DAC960_V3_OutboundDoorBellRegisterOffset = 0x41, + DAC960_V3_InterruptEnableRegisterOffset = 0x43 +} +DAC960_V3_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V3 Inbound Door Bell Register. +*/ + +typedef union DAC960_V3_InboundDoorBellRegister +{ + unsigned char All; + struct { + boolean NewCommand:1; /* Bit 0 */ + boolean AcknowledgeStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + unsigned char :4; /* Bits 4-7 */ + } Write; + struct { + boolean MailboxFull:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V3_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V3 Outbound Door Bell Register. +*/ + +typedef union DAC960_V3_OutboundDoorBellRegister +{ + unsigned char All; + struct { + boolean AcknowledgeInterrupt:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Write; + struct { + boolean StatusAvailable:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V3_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V3 Interrupt Enable Register. +*/ + +typedef union DAC960_V3_InterruptEnableRegister +{ + unsigned char All; + struct { + boolean EnableInterrupts:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Bits; +} +DAC960_V3_InterruptEnableRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V3 Controller Interface Registers. +*/ + +static inline +void DAC960_V3_NewCommand(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.NewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeStatus = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.MailboxFull; +} + +static inline +void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.StatusAvailable; +} + +static inline +void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = 0; + InterruptEnableRegister.Bits.EnableInterrupts = true; + writeb(InterruptEnableRegister.All, + ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); +} + +static inline +void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = 0; + InterruptEnableRegister.Bits.EnableInterrupts = false; + writeb(InterruptEnableRegister.All, + ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); +} + +static inline +boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = + readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); + return InterruptEnableRegister.Bits.EnableInterrupts; +} + +static inline +void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V3_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset); +} + + +/* + Define compatibility macros between Linux 2.0 and Linux 2.1. +*/ + +#if LINUX_VERSION_CODE < 0x20100 + +#define MODULE_PARM(Variable, Type) +#define ioremap_nocache(Offset, Size) vremap(Offset, Size) +#define iounmap(Address) vfree(Address) + +#endif + + +/* + Define prototypes for the forward referenced DAC960 Driver Internal Functions. +*/ + +static void DAC960_FinalizeController(DAC960_Controller_T *); +static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *); +static void DAC960_RequestFunction0(void); +static void DAC960_RequestFunction1(void); +static void DAC960_RequestFunction2(void); +static void DAC960_RequestFunction3(void); +static void DAC960_RequestFunction4(void); +static void DAC960_RequestFunction5(void); +static void DAC960_RequestFunction6(void); +static void DAC960_RequestFunction7(void); +static void DAC960_InterruptHandler(int, void *, Registers_T *); +static void DAC960_QueueMonitoringCommand(DAC960_Command_T *); +static void DAC960_MonitoringTimerFunction(unsigned long); +static int DAC960_Open(Inode_T *, File_T *); +static int DAC960_Release(Inode_T *, File_T *); +static int DAC960_IOCTL(Inode_T *, File_T *, unsigned int, unsigned long); +static int DAC960_UserIOCTL(Inode_T *, File_T *, unsigned int, unsigned long); +static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *); +static void DAC960_Message(DAC960_MessageLevel_T, char *, + DAC960_Controller_T *, ...); +static void DAC960_CreateProcEntries(void); +static void DAC960_DestroyProcEntries(void); + + +/* + Export the Kernel Mode IOCTL interface. +*/ + +EXPORT_SYMBOL(DAC960_KernelIOCTL); + + +#endif /* DAC960_DriverVersion */ diff --git a/drivers/block/MAKEDEV-IDE45 b/drivers/block/MAKEDEV-IDE45 deleted file mode 100644 index c55a9b3cf..000000000 --- a/drivers/block/MAKEDEV-IDE45 +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/sh -# -# Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu> -# -# The song goes, "I did it the hard way..........." -# - -if [ ! -f /dev/hdi ]; then \ - echo "Making IDE4 Primary Devices hdi's"; \ - mknod /dev/hdi b 56 0; \ - mknod /dev/hdi1 b 56 1; \ - mknod /dev/hdi2 b 56 2; \ - mknod /dev/hdi3 b 56 3; \ - mknod /dev/hdi4 b 56 4; \ - mknod /dev/hdi5 b 56 5; \ - mknod /dev/hdi6 b 56 6; \ - mknod /dev/hdi7 b 56 7; \ - mknod /dev/hdi8 b 56 8; \ - mknod /dev/hdi9 b 56 9; \ - mknod /dev/hdi10 b 56 10; \ - mknod /dev/hdi11 b 56 11; \ - mknod /dev/hdi12 b 56 12; \ - mknod /dev/hdi13 b 56 13; \ - mknod /dev/hdi14 b 56 14; \ - mknod /dev/hdi15 b 56 15; \ - mknod /dev/hdi16 b 56 16; \ - chown root.disk /dev/hdi*; \ - chmod 660 /dev/hdi*; \ -fi - -if [ ! -f /dev/hdj ]; then \ - echo "Making IDE4 Secondary Devices hdj's"; \ - mknod /dev/hdj b 56 64; \ - mknod /dev/hdj1 b 56 65; \ - mknod /dev/hdj2 b 56 66; \ - mknod /dev/hdj3 b 56 67; \ - mknod /dev/hdj4 b 56 68; \ - mknod /dev/hdj5 b 56 69; \ - mknod /dev/hdj6 b 56 70; \ - mknod /dev/hdj7 b 56 71; \ - mknod /dev/hdj8 b 56 72; \ - mknod /dev/hdj9 b 56 73; \ - mknod /dev/hdj10 b 56 74; \ - mknod /dev/hdj11 b 56 75; \ - mknod /dev/hdj12 b 56 76; \ - mknod /dev/hdj13 b 56 77; \ - mknod /dev/hdj14 b 56 78; \ - mknod /dev/hdj15 b 56 79; \ - mknod /dev/hdj16 b 56 80; \ - chown root.disk /dev/hdj*; \ - chmod 660 /dev/hdj*; \ -fi - -if [ ! -f /dev/hdk ]; then \ - echo "Making IDE5 Primary Devices hdk's"; \ - mknod /dev/hdk b 57 0; \ - mknod /dev/hdk1 b 57 1; \ - mknod /dev/hdk2 b 57 2; \ - mknod /dev/hdk3 b 57 3; \ - mknod /dev/hdk4 b 57 4; \ - mknod /dev/hdk5 b 57 5; \ - mknod /dev/hdk6 b 57 6; \ - mknod /dev/hdk7 b 57 7; \ - mknod /dev/hdk8 b 57 8; \ - mknod /dev/hdk9 b 57 9; \ - mknod /dev/hdk10 b 57 10; \ - mknod /dev/hdk11 b 57 11; \ - mknod /dev/hdk12 b 57 12; \ - mknod /dev/hdk13 b 57 13; \ - mknod /dev/hdk14 b 57 14; \ - mknod /dev/hdk15 b 57 15; \ - mknod /dev/hdk16 b 57 16; \ - chown root.disk /dev/hdk*; \ - chmod 660 /dev/hdk*; \ -fi - -if [ ! -f /dev/hdl ]; then \ - echo "Making IDE5 Secondary Devices hdl's"; \ - mknod /dev/hdl b 57 64; \ - mknod /dev/hdl1 b 57 65; \ - mknod /dev/hdl2 b 57 66; \ - mknod /dev/hdl3 b 57 67; \ - mknod /dev/hdl4 b 57 68; \ - mknod /dev/hdl5 b 57 69; \ - mknod /dev/hdl6 b 57 70; \ - mknod /dev/hdl7 b 57 71; \ - mknod /dev/hdl8 b 57 72; \ - mknod /dev/hdl9 b 57 73; \ - mknod /dev/hdl10 b 57 74; \ - mknod /dev/hdl11 b 57 75; \ - mknod /dev/hdl12 b 57 76; \ - mknod /dev/hdl13 b 57 77; \ - mknod /dev/hdl14 b 57 78; \ - mknod /dev/hdl15 b 57 79; \ - mknod /dev/hdl16 b 57 80; \ - chown root.disk /dev/hdl*; \ - chmod 660 /dev/hdl*; \ -fi - diff --git a/drivers/block/MAKEDEV-IDE67 b/drivers/block/MAKEDEV-IDE67 deleted file mode 100644 index 27728be28..000000000 --- a/drivers/block/MAKEDEV-IDE67 +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/sh -# -# Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu> -# -# The song goes, "I did it the hard way..........." -# - -if [ ! -f /dev/hdm ]; then \ - echo "Making IDE6 Primary Devices hdm's"; \ - mknod /dev/hdm b 88 0; \ - mknod /dev/hdm1 b 88 1; \ - mknod /dev/hdm2 b 88 2; \ - mknod /dev/hdm3 b 88 3; \ - mknod /dev/hdm4 b 88 4; \ - mknod /dev/hdm5 b 88 5; \ - mknod /dev/hdm6 b 88 6; \ - mknod /dev/hdm7 b 88 7; \ - mknod /dev/hdm8 b 88 8; \ - mknod /dev/hdm9 b 88 9; \ - mknod /dev/hdm10 b 88 10; \ - mknod /dev/hdm11 b 88 11; \ - mknod /dev/hdm12 b 88 12; \ - mknod /dev/hdm13 b 88 13; \ - mknod /dev/hdm14 b 88 14; \ - mknod /dev/hdm15 b 88 15; \ - mknod /dev/hdm16 b 88 16; \ - chown root.disk /dev/hdm*; \ - chmod 660 /dev/hdm*; \ -fi - -if [ ! -f /dev/hdn ]; then \ - echo "Making IDE6 Secondary Devices hdn's"; \ - mknod /dev/hdn b 88 64; \ - mknod /dev/hdn1 b 88 65; \ - mknod /dev/hdn2 b 88 66; \ - mknod /dev/hdn3 b 88 67; \ - mknod /dev/hdn4 b 88 68; \ - mknod /dev/hdn5 b 88 69; \ - mknod /dev/hdn6 b 88 70; \ - mknod /dev/hdn7 b 88 71; \ - mknod /dev/hdn8 b 88 72; \ - mknod /dev/hdn9 b 88 73; \ - mknod /dev/hdn10 b 88 74; \ - mknod /dev/hdn11 b 88 75; \ - mknod /dev/hdn12 b 88 76; \ - mknod /dev/hdn13 b 88 77; \ - mknod /dev/hdn14 b 88 78; \ - mknod /dev/hdn15 b 88 79; \ - mknod /dev/hdn16 b 88 80; \ - chown root.disk /dev/hdn*; \ - chmod 660 /dev/hdn*; \ -fi - -if [ ! -f /dev/hdo ]; then \ - echo "Making IDE7 Primary Devices hdo's"; \ - mknod /dev/hdo b 89 0; \ - mknod /dev/hdo1 b 89 1; \ - mknod /dev/hdo2 b 89 2; \ - mknod /dev/hdo3 b 89 3; \ - mknod /dev/hdo4 b 89 4; \ - mknod /dev/hdo5 b 89 5; \ - mknod /dev/hdo6 b 89 6; \ - mknod /dev/hdo7 b 89 7; \ - mknod /dev/hdo8 b 89 8; \ - mknod /dev/hdo9 b 89 9; \ - mknod /dev/hdo10 b 89 10; \ - mknod /dev/hdo11 b 89 11; \ - mknod /dev/hdo12 b 89 12; \ - mknod /dev/hdo13 b 89 13; \ - mknod /dev/hdo14 b 89 14; \ - mknod /dev/hdo15 b 89 15; \ - mknod /dev/hdo16 b 89 16; \ - chown root.disk /dev/hdo*; \ - chmod 660 /dev/hdo*; \ -fi - -if [ ! -f /dev/hdp ]; then \ - echo "Making IDE7 Secondary Devices hdp's"; \ - mknod /dev/hdp b 89 64; \ - mknod /dev/hdp1 b 89 65; \ - mknod /dev/hdp2 b 89 66; \ - mknod /dev/hdp3 b 89 67; \ - mknod /dev/hdp4 b 89 68; \ - mknod /dev/hdp5 b 89 69; \ - mknod /dev/hdp6 b 89 70; \ - mknod /dev/hdp7 b 89 71; \ - mknod /dev/hdp8 b 89 72; \ - mknod /dev/hdp9 b 89 73; \ - mknod /dev/hdp10 b 89 74; \ - mknod /dev/hdp11 b 89 75; \ - mknod /dev/hdp12 b 89 76; \ - mknod /dev/hdp13 b 89 77; \ - mknod /dev/hdp14 b 89 78; \ - mknod /dev/hdp15 b 89 79; \ - mknod /dev/hdp16 b 89 80; \ - chown root.disk /dev/hdp*; \ - chmod 660 /dev/hdp*; \ -fi - diff --git a/drivers/block/Makefile b/drivers/block/Makefile index bb03a3200..abc2242dc 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -20,7 +20,7 @@ ALL_SUB_DIRS := $(SUB_DIRS) paride L_TARGET := block.a -L_OBJS := genhd.o +L_OBJS := genhd.o cmos-probe.o M_OBJS := MOD_LIST_NAME := BLOCK_MODULES LX_OBJS := ll_rw_blk.o blkpg.o @@ -54,6 +54,10 @@ else endif endif +ifeq ($(CONFIG_BLK_DEV_SWIM_IOP),y) + L_OBJS += swim_iop.o +endif + ifeq ($(CONFIG_ATARI_ACSI),y) LX_OBJS += acsi.o else @@ -94,116 +98,140 @@ else endif endif -ifeq ($(CONFIG_BLK_DEV_HD),y) -L_OBJS += hd.o +# +# IDE-STUFF +# + +ifeq ($(CONFIG_BLK_DEV_AEC6210),y) +IDE_OBJS += aec6210.o endif -ifeq ($(CONFIG_BLK_DEV_RZ1000),y) -IDE_OBJS += rz1000.o +ifeq ($(CONFIG_BLK_DEV_ALI14XX),y) +IDE_OBJS += ali14xx.o endif -ifeq ($(CONFIG_BLK_DEV_CMD640),y) -IDE_OBJS += cmd640.o +ifeq ($(CONFIG_BLK_DEV_ALI15X3),y) +IDE_OBJS += alim15x3.o endif -ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y) -IDE_OBJS += ide-pmac.o +ifeq ($(CONFIG_BLK_DEV_BUDDHA),y) +IDE_OBJS += buddha.o endif -ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) -IDE_OBJS += ide-pci.o +ifeq ($(CONFIG_BLK_DEV_CMD640),y) +IDE_OBJS += cmd640.o endif -ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) -IDE_OBJS += ide-dma.o +ifeq ($(CONFIG_BLK_DEV_CMD646),y) +IDE_OBJS += cmd646.o +endif + +ifeq ($(CONFIG_BLK_DEV_CY82C693),y) +IDE_OBJS += cy82c693.o endif ifeq ($(CONFIG_BLK_DEV_DTC2278),y) IDE_OBJS += dtc2278.o endif -ifeq ($(CONFIG_BLK_DEV_HT6560B),y) -IDE_OBJS += ht6560b.o +ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y) +IDE_OBJS += falconide.o endif -ifeq ($(CONFIG_BLK_DEV_QD6580),y) -IDE_OBJS += qd6580.o +ifeq ($(CONFIG_BLK_DEV_GAYLE),y) +IDE_OBJS += gayle.o endif -ifeq ($(CONFIG_BLK_DEV_UMC8672),y) -IDE_OBJS += umc8672.o +ifeq ($(CONFIG_BLK_DEV_Q40IDE),y) +IDE_OBJS += q40ide.o endif -ifeq ($(CONFIG_BLK_DEV_ALI14XX),y) -IDE_OBJS += ali14xx.o +ifeq ($(CONFIG_BLK_DEV_HD),y) +L_OBJS += hd.o endif -ifeq ($(CONFIG_BLK_DEV_PDC4030),y) -IDE_OBJS += pdc4030.o +ifeq ($(CONFIG_BLK_DEV_HPT34X),y) +IDE_OBJS += hpt34x.o endif -ifeq ($(CONFIG_BLK_DEV_TRM290),y) -IDE_OBJS += trm290.o +ifeq ($(CONFIG_BLK_DEV_HPT366),y) +IDE_OBJS += hpt366.o endif -ifeq ($(CONFIG_BLK_DEV_OPTI621),y) -IDE_OBJS += opti621.o +ifeq ($(CONFIG_BLK_DEV_HT6560B),y) +IDE_OBJS += ht6560b.o endif -ifeq ($(CONFIG_BLK_DEV_NS87415),y) -IDE_OBJS += ns87415.o +ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y) +IDE_OBJS += icside.o endif -ifeq ($(CONFIG_BLK_DEV_VIA82C586),y) -IDE_OBJS += via82c586.o +ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) +IDE_OBJS += ide-dma.o endif -ifeq ($(CONFIG_BLK_DEV_GAYLE),y) -IDE_OBJS += gayle.o +ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) +IDE_OBJS += ide-pci.o endif -ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y) -IDE_OBJS += falconide.o +ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y) +IDE_OBJS += ide-pmac.o endif ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y) IDE_OBJS += macide.o endif -ifeq ($(CONFIG_BLK_DEV_BUDDHA),y) -IDE_OBJS += buddha.o -endif - -ifeq ($(CONFIG_BLK_DEV_CMD646),y) -IDE_OBJS += cmd646.o +ifeq ($(CONFIG_BLK_DEV_NS87415),y) +IDE_OBJS += ns87415.o endif -ifeq ($(CONFIG_BLK_DEV_SL82C105),y) -IDE_OBJS += sl82c105.o +ifeq ($(CONFIG_BLK_DEV_OPTI621),y) +IDE_OBJS += opti621.o endif -ifeq ($(CONFIG_BLK_DEV_ALI15X3),y) -IDE_OBJS += alim15x3.o +ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) +IDE_OBJS += pdc202xx.o endif -ifeq ($(CONFIG_BLK_DEV_CY82C693),y) -IDE_OBJS += cy82c693.o +ifeq ($(CONFIG_BLK_DEV_PDC4030),y) +IDE_OBJS += pdc4030.o endif ifeq ($(CONFIG_BLK_DEV_PIIX),y) IDE_OBJS += piix.o endif -ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) -IDE_OBJS += pdc202xx.o +ifeq ($(CONFIG_BLK_DEV_QD6580),y) +IDE_OBJS += qd6580.o endif -ifeq ($(CONFIG_BLK_DEV_AEC6210),y) -IDE_OBJS += aec6210.o +ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y) +IDE_OBJS += rapide.o endif -ifeq ($(CONFIG_BLK_DEV_HPT34X),y) -IDE_OBJS += hpt34x.o +ifeq ($(CONFIG_BLK_DEV_RZ1000),y) +IDE_OBJS += rz1000.o +endif + +ifeq ($(CONFIG_BLK_DEV_SIS5513),y) +IDE_OBJS += sis5513.o +endif + +ifeq ($(CONFIG_BLK_DEV_SL82C105),y) +IDE_OBJS += sl82c105.o +endif + +ifeq ($(CONFIG_BLK_DEV_TRM290),y) +IDE_OBJS += trm290.o +endif + +ifeq ($(CONFIG_BLK_DEV_UMC8672),y) +IDE_OBJS += umc8672.o +endif + +ifeq ($(CONFIG_BLK_DEV_VIA82C586),y) +IDE_OBJS += via82c586.o endif ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored @@ -282,6 +310,14 @@ else endif endif +ifeq ($(CONFIG_BLK_DEV_DAC960),y) +LX_OBJS += DAC960.o +else + ifeq ($(CONFIG_BLK_DEV_DAC960),m) + MX_OBJS += DAC960.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_MD),y) LX_OBJS += md.o diff --git a/drivers/block/README.buddha b/drivers/block/README.buddha new file mode 100644 index 000000000..d3b7bc73f --- /dev/null +++ b/drivers/block/README.buddha @@ -0,0 +1,210 @@ + +The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by +Geert Uytterhoeven based on the following specifications: + +------------------------------------------------------------------------ + +Register map of the Buddha IDE controller and the +Buddha-part of the Catweasel Zorro-II version + +The Autoconfiguration has been implemented just as Commodore +described in their manuals, no tricks have been used (for +example leaving some address lines out of the equations...). +If you want to configure the board yourself (for example let +a Linux kernel configure the card), look at the Commodore +Docs. Reading the nibbles should give this information: + +Vendor number: 4626 ($1212) +product number: 0 (42 for Catweasel Z-II) +Serial number: 0 +Rom-vector: $1000 + +The card should be a Z-II board, size 64K, not for freemem +list, Rom-Vektor is valid, no second Autoconfig-board on the +same card, no space preferrence, supports "Shutup_forever". + +Setting the base address should be done in two steps, just +as the Amiga Kickstart does: The lower nibble of the 8-Bit +address is written to $4a, then the whole Byte is written to +$48, while it doesn't matter how often you're writing to $4a +as long as $48 is not touched. After $48 has been written, +the whole card disappears from $e8 and is mapped to the new +addrress just written. Make shure $4a is written befor $48, +otherwise your chance is only 1:16 to find the board :-). + +The local memory-map is even active when mapped to $e8: + +$0-$7e Autokonfig-space, see Z-II docs. + +$80-$7fd reserved + +$7fe Speed-select Register: Read & Write + (description see further down) + +$800-$8ff IDE-Select 0 (Port 0, Register set 0) + +$900-$9ff IDE-Select 1 (Port 0, Register set 1) + +$a00-$aff IDE-Select 2 (Port 1, Register set 0) + +$b00-$bff IDE-Select 3 (Port 1, Register set 1) + +$c00-$cff IDE-Select 4 (Port 2, Register set 0, + Catweasel only!) + +$d00-$dff IDE-Select 5 (Port 3, Register set 1, + Catweasel only!) + +$e00-$eff local expansion port, on Catweasel Z-II the + Catweasel registers are also mapped here. + Never touch, use multidisk.device! + +$f00 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 0. + +$f01-$f3f mirror of $f00 + +$f40 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 1. + +$f41-$f7f mirror of $f40 + +$f80 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 2. + (Catweasel only!) + +$f81-$fbf mirror of $f80 + +$fc0 write-only: Writing any value to this + register enables IRQs to be passed from the + IDE ports to the Zorro bus. This mechanism + has been implemented to be compatible with + harddisks that are either defective or have + a buggy firmware and pull the IRQ line up + while starting up. If interrupts would + always be passed to the bus, the computer + might not start up. Once enabled, this flag + can not be disabled again. The level of the + flag can not be determined by software + (what for? Write to me if it's necessary!). + +$fc1-$fff mirror of $fc0 + +$1000-$ffff Buddha-Rom with offset $1000 in the rom + chip. The addresses $0 to $fff of the rom + chip cannot be read. Rom is Byte-wide and + mapped to even addresses. + +The IDE ports issue an INT2. You can read the level of the +IRQ-lines of the IDE-ports by reading from the three (two +for Buddha-only) registers $f00, $f40 and $f80. This way +more than one I/O request can be handled and you can easily +determine what driver has to serve the INT2. Buddha and +Catweasel expansion boards can issue an INT6. A seperate +memory map is available for the I/O module and the sysop's +I/O module. + +The IDE ports are fed by the address lines A2 to A4, just as +the Amiga 1200 and Amiga 4000 IDE ports are. This way +existing drivers can be easily ported to Buddha. A move.l +polls two words out of the same address of IDE port since +every word is mirrored once. movem is not possible, but +it's not necessary either, because you can only speedup +68000 systems with this technique. A 68020 system with +fastmem is faster with move.l. + +If you're using the mirrored registers of the IDE-ports with +A6=1, the Buddha doesn't care about the speed that you have +selected in the speed register (see further down). With +A6=1 (for example $840 for port 0, register set 0), a 780ns +access is being made. These registers should be used for a +command access to the harddisk/CD-Rom, since command +accesses are Byte-wide and have to be made slower according +to the ATA-X3T9 manual. + +Now for the speed-register: The register is byte-wide, and +only the upper three bits are used (Bits 7 to 5). Bit 4 +must always be set to 1 to be compatible with later Buddha +versions (if I'll ever update this one). I presume that +I'll never use the lower four bits, but they have to be set +to 1 by definition. + The values in this table have to be shifted 5 bits to the +left and or'd with $1f (this sets the lower 5 bits). + +All the timings have in common: Select and IOR/IOW rise at +the same time. IOR and IOW have a propagation delay of +about 30ns to the clocks on the Zorro bus, that's why the +values are no multiple of 71. One clock-cycle is 71ns long +(exactly 70,5 at 14,18 Mhz on PAL systems). + +value 0 (Default after reset) + +497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) +(same timing as the Amiga 1200 does on it's IDE port without +accelerator card) + +value 1 + +639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) + +value 2 + +781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) + +value 3 + +355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + +value 4 + +355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) + +value 5 + +355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) + +value 6 + +1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) + +value 7 + +355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + +When accessing IDE registers with A6=1 (for example $84x), +the timing will always be mode 0 8-bit compatible, no matter +what you have selected in the speed register: + +781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. + +All the timings with a very short select-signal (the 355ns +fast accesses) depend on the accelerator card used in the +system: Sometimes two more clock cycles are inserted by the +bus interface, making the whole access 497ns long. This +doesn't affect the reliability of the controller nor the +performance of the card, since this doesn't happen very +often. + +All the timings are calculated and only confirmed by +measurements that allowed me to count the clock cycles. If +the system is clocked by an oscillator other than 28,37516 +Mhz (for example the NTSC-frequency 28,63636 Mhz), each +clock cycle is shortened to a bit less than 70ns (not worth +mentioning). You could think of a small performance boost +by overclocking the system, but you would either need a +multisync monitor, or a graphics card, and your internal +diskdrive would go crazy, that's why you shouldn't tune your +Amiga this way. + +Giving you the possibility to write software that is +compatible with both the Buddha and the Catweasel Z-II, The +Buddha acts just like a Catweasel Z-II with no device +connected to the third IDE-port. The IRQ-register $f80 +always shows a "no IRQ here" on the Buddha, and accesses to +the third IDE port are going into data's Nirwana on the +Buddha. + + Jens Schönfeld february 19th, 1997 + updated may 27th, 1997 + eMail: sysop@nostlgic.tng.oche.de + diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index ea0e989f8..80aa52472 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -253,17 +253,8 @@ static int CurrentNSect; static char *CurrentBuffer; -#define SET_TIMER() \ - do { \ - del_timer( &acsi_timer ); \ - acsi_timer.expires = jiffies + ACSI_TIMEOUT; \ - add_timer( &acsi_timer ); \ - } while(0) - -#define CLEAR_TIMER() \ - do { \ - del_timer( &acsi_timer ); \ - } while(0) +#define SET_TIMER() mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT) +#define CLEAR_TIMER() del_timer(&acsi_timer) static unsigned long STramMask; #define STRAM_ADDR(a) (((a) & STramMask) == 0) @@ -425,8 +416,8 @@ int acsi_wait_for_IRQ( unsigned timeout ) { if (INT_LEVEL < 6) { - unsigned long maxjif; - for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); ) + unsigned long maxjif = jiffies + timeout; + while (time_before(jiffies, maxjif)) if (!(mfp.par_dt_reg & 0x20)) return( 1 ); } else { @@ -442,8 +433,8 @@ int acsi_wait_for_noIRQ( unsigned timeout ) { if (INT_LEVEL < 6) { - unsigned long maxjif; - for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); ) + unsigned long maxjif = jiffies + timeout; + while (time_before(jiffies, maxjif)) if (mfp.par_dt_reg & 0x20) return( 1 ); } else { @@ -502,7 +493,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, i #endif rwflag = rwflag ? 0x100 : 0; - paddr = VTOP( buffer ); + paddr = virt_to_phys( buffer ); acsi_delay_end(COMMAND_DELAY); DISABLE_IRQ(); @@ -610,7 +601,7 @@ static int acsi_reqsense( char *buffer, int targ, int lun) if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); if (!acsi_wait_for_IRQ( 10 )) return( 0 ); acsi_getstatus(); - dma_cache_maintenance( VTOP(buffer), 16, 0 ); + dma_cache_maintenance( virt_to_phys(buffer), 16, 0 ); return( 1 ); } @@ -809,7 +800,7 @@ static void read_intr( void ) return; } - dma_cache_maintenance( VTOP(CurrentBuffer), CurrentNSect*512, 0 ); + dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 ); if (CurrentBuffer == acsi_buffer) copy_from_acsibuffer(); @@ -1030,7 +1021,7 @@ static void redo_acsi_request( void ) * consecutive buffers and thus can be done with a single command. */ buffer = CURRENT->buffer; - pbuffer = VTOP(buffer); + pbuffer = virt_to_phys(buffer); nsect = CURRENT->current_nr_sectors; CurrentNReq = 1; @@ -1052,7 +1043,7 @@ static void redo_acsi_request( void ) unsigned long pendadr, pnewadr; pendadr = pbuffer + nsect*512; while( (bh = bh->b_reqnext) ) { - pnewadr = VTOP(bh->b_data); + pnewadr = virt_to_phys(bh->b_data); if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break; nsect += bh->b_size >> 9; pendadr = pnewadr + bh->b_size; @@ -1814,7 +1805,7 @@ int acsi_init( void ) unregister_blkdev( MAJOR_NR, "ad" ); return -ENOMEM; } - phys_acsi_buffer = VTOP( acsi_buffer ); + phys_acsi_buffer = virt_to_phys( acsi_buffer ); STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index b341c39c4..d718075e2 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -413,8 +413,8 @@ static void start_print( int device ) CMDSET_TARG_LUN( slmprint_cmd, sip->target, sip->lun ); cmd = slmprint_cmd; - paddr = VTOP( SLMBuffer ); - dma_cache_maintenance( paddr, VTOP(BufferP)-paddr, 1 ); + paddr = virt_to_phys( SLMBuffer ); + dma_cache_maintenance( paddr, virt_to_phys(BufferP)-paddr, 1 ); DISABLE_IRQ(); /* Low on A1 */ @@ -466,7 +466,7 @@ static void slm_interrupt(int irc, void *data, struct pt_regs *fp) addr = get_dma_addr(); stat = acsi_getstatus(); SLMError = (stat < 0) ? SLMSTAT_ACSITO : - (addr < VTOP(BufferP)) ? SLMSTAT_NOTALL : + (addr < virt_to_phys(BufferP)) ? SLMSTAT_NOTALL : stat; dma_wd.dma_mode_status = 0x80; diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c index 03ef37c90..c52d8450d 100644 --- a/drivers/block/aec6210.c +++ b/drivers/block/aec6210.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/aec6210.c Version 0.01 Nov 17, 1998 + * linux/drivers/block/aec6210.c Version 0.01 Nov 17, 1998 * - * Copyright (C) 1998 Andre Hedrick (hedrick@astro.dyer.vanderbilt.edu) + * Copyright (C) 1998-99 Andre Hedrick * * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 * pio 1 :: 40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02 @@ -31,7 +31,6 @@ * NO-Devices * 40: 00 00 00 00 00 00 00 00 02 05 a6 00 00 02 00 02 * 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00 - */ #include <linux/types.h> @@ -51,13 +50,11 @@ #include <asm/io.h> #include <asm/irq.h> -__initfunc(unsigned int pci_init_aec6210 (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) { - if (dev->rom_address) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, - dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", - name, dev->rom_address); + if (dev->resource[PCI_ROM_RESOURCE].start) { + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } return dev->irq; } diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c index 4ea590fa2..b7a0a5c4f 100644 --- a/drivers/block/alim15x3.c +++ b/drivers/block/alim15x3.c @@ -110,7 +110,7 @@ static void ali15x3_tune_drive (ide_drive_t *drive, byte pio) } -__initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) { byte confreg0 = 0, confreg1 =0, progif = 0; int errors = 0; @@ -194,7 +194,7 @@ int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -__initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif)) +void __init ide_init_ali15x3 (ide_hwif_t *hwif) { struct pci_dev *dev; byte ideic, inmir, iderev; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 8e3459d3f..b27d12095 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -135,10 +135,10 @@ MODULE_PARM(fd_def_df0,"l"); static struct fd_drive_type drive_types[] = { /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/ /* warning: times are now in milliseconds (ms) */ - { FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80,161, 3, 18, 1}, - { FD_HD_3, "HD 3.5", 80, 2, 28344, 27258, 2, 80,161, 3, 18, 1}, - { FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2}, - { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +{ FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80,161, 3, 18, 1}, +{ FD_HD_3, "HD 3.5", 80, 2, 28344, 27258, 2, 80,161, 3, 18, 1}, +{ FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2}, +{ FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); @@ -150,8 +150,8 @@ static int floppy_blocksizes[256]={0,}; static int amiga_read(int), dos_read(int); static void amiga_write(int), dos_write(int); static struct fd_data_type data_types[] = { - { "Amiga", 11 , amiga_read, amiga_write}, - { "MS-Dos", 9, dos_read, dos_write} + { "Amiga", 11 , amiga_read, amiga_write}, + { "MS-Dos", 9, dos_read, dos_write} }; /* current info on each unit */ @@ -189,8 +189,8 @@ static DECLARE_WAIT_QUEUE_HEAD(wait_fd_block); /* MS-Dos MFM Coding tables (should go quick and easy) */ static unsigned char mfmencode[16]={ - 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, - 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 }; static unsigned char mfmdecode[128]; @@ -231,29 +231,29 @@ static int fd_device[4] = { 0,0,0,0 }; static void ms_isr(int irq, void *dummy, struct pt_regs *fp) { -ms_busy = -1; -wake_up(&ms_wait); + ms_busy = -1; + wake_up(&ms_wait); } /* all waits are queued up A more generic routine would do a schedule a la timer.device */ static void ms_delay(int ms) { - unsigned long flags; - int ticks; - if (ms > 0) { - save_flags(flags); - cli(); - while (ms_busy == 0) - sleep_on(&ms_wait); - ms_busy = 0; - restore_flags(flags); - ticks = MS_TICKS*ms-1; - ciaa.tblo=ticks%256; - ciaa.tbhi=ticks/256; - ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */ - sleep_on(&ms_wait); - } + unsigned long flags; + int ticks; + if (ms > 0) { + save_flags(flags); + cli(); + while (ms_busy == 0) + sleep_on(&ms_wait); + ms_busy = 0; + restore_flags(flags); + ticks = MS_TICKS*ms-1; + ciaa.tblo=ticks%256; + ciaa.tbhi=ticks/256; + ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */ + sleep_on(&ms_wait); + } } /* Hardware semaphore */ @@ -267,33 +267,33 @@ static inline int try_fdc(int drive) static void get_fdc(int drive) { -unsigned long flags; + unsigned long flags; - drive &= 3; + drive &= 3; #ifdef DEBUG - printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested); + printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested); #endif - save_flags(flags); - cli(); - while (!try_fdc(drive)) - sleep_on(&fdc_wait); - fdc_busy = drive; - fdc_nested++; - restore_flags(flags); + save_flags(flags); + cli(); + while (!try_fdc(drive)) + sleep_on(&fdc_wait); + fdc_busy = drive; + fdc_nested++; + restore_flags(flags); } static inline void rel_fdc(void) { #ifdef DEBUG - if (fdc_nested == 0) - printk("fd: unmatched rel_fdc\n"); - printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested); + if (fdc_nested == 0) + printk("fd: unmatched rel_fdc\n"); + printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested); #endif - fdc_nested--; - if (fdc_nested == 0) { - fdc_busy = -1; - wake_up(&fdc_wait); - } + fdc_nested--; + if (fdc_nested == 0) { + fdc_busy = -1; + wake_up(&fdc_wait); + } } static void fd_select (int drive) @@ -395,9 +395,9 @@ static int fd_motor_on(int nr) static void fd_motor_off(unsigned long drive) { -long calledfromint; + long calledfromint; #ifdef MODULE -long decusecount; + long decusecount; decusecount = drive & 0x40000000; #endif @@ -416,18 +416,18 @@ long decusecount; #ifdef MODULE /* -this is the last interrupt for any drive access, happens after -release (from floppy_off). So we have to wait until now to decrease -the use count. + this is the last interrupt for any drive access, happens after + release (from floppy_off). So we have to wait until now to decrease + the use count. */ - if (decusecount) - MOD_DEC_USE_COUNT; + if (decusecount) + MOD_DEC_USE_COUNT; #endif } static void floppy_off (unsigned int nr) { -int drive; + int drive; drive = nr & 3; del_timer(motor_off_timer + drive); @@ -588,29 +588,29 @@ static unsigned long fd_get_drive_id(int drive) * type. */ if(drive == 0 && id == FD_NODRIVE) - { + { id = fd_def_df0; printk(KERN_NOTICE "fd: drive 0 didn't identify, setting default %08lx\n", (ulong)fd_def_df0); - } + } /* return the ID value */ return (id); } static void fd_block_done(int irq, void *dummy, struct pt_regs *fp) { - if (block_flag) - custom.dsklen = 0x4000; - - if (block_flag == 2) { /* writing */ - writepending = 2; - post_write_timer.expires = jiffies + 1; /* at least 2 ms */ - post_write_timer.data = selected; - add_timer(&post_write_timer); - } - else { /* reading */ - block_flag = 0; - wake_up (&wait_fd_block); - } + if (block_flag) + custom.dsklen = 0x4000; + + if (block_flag == 2) { /* writing */ + writepending = 2; + post_write_timer.expires = jiffies + 1; /* at least 2 ms */ + post_write_timer.data = selected; + add_timer(&post_write_timer); + } + else { /* reading */ + block_flag = 0; + wake_up (&wait_fd_block); + } } static void raw_read(int drive) @@ -680,17 +680,17 @@ static int raw_write(int drive) static void post_write (unsigned long drive) { #ifdef DEBUG - printk("post_write for drive %ld\n",drive); + printk("post_write for drive %ld\n",drive); #endif - drive &= 3; - custom.dsklen = 0; - block_flag = 0; - writepending = 0; - writefromint = 0; - unit[drive].dirty = 0; - wake_up(&wait_fd_block); - fd_deselect(drive); - rel_fdc(); /* corresponds to get_fdc() in raw_write */ + drive &= 3; + custom.dsklen = 0; + block_flag = 0; + writepending = 0; + writefromint = 0; + unit[drive].dirty = 0; + wake_up(&wait_fd_block); + fd_deselect(drive); + rel_fdc(); /* corresponds to get_fdc() in raw_write */ } @@ -727,7 +727,7 @@ static inline unsigned long checksum(unsigned long *addr, int len) } static unsigned long decode (unsigned long *data, unsigned long *raw, - int len) + int len) { ulong *odd, *even; @@ -822,34 +822,34 @@ static int amiga_read(int drive) static void encode(unsigned long data, unsigned long *dest) { - unsigned long data2; + unsigned long data2; - data &= 0x55555555; - data2 = data ^ 0x55555555; - data |= ((data2 >> 1) | 0x80000000) & (data2 << 1); + data &= 0x55555555; + data2 = data ^ 0x55555555; + data |= ((data2 >> 1) | 0x80000000) & (data2 << 1); - if (*(dest - 1) & 0x00000001) - data &= 0x7FFFFFFF; + if (*(dest - 1) & 0x00000001) + data &= 0x7FFFFFFF; - *dest = data; + *dest = data; } static void encode_block(unsigned long *dest, unsigned long *src, int len) { - int cnt, to_cnt = 0; - unsigned long data; - - /* odd bits */ - for (cnt = 0; cnt < len / 4; cnt++) { - data = src[cnt] >> 1; - encode(data, dest + to_cnt++); - } - - /* even bits */ - for (cnt = 0; cnt < len / 4; cnt++) { - data = src[cnt]; - encode(data, dest + to_cnt++); - } + int cnt, to_cnt = 0; + unsigned long data; + + /* odd bits */ + for (cnt = 0; cnt < len / 4; cnt++) { + data = src[cnt] >> 1; + encode(data, dest + to_cnt++); + } + + /* even bits */ + for (cnt = 0; cnt < len / 4; cnt++) { + data = src[cnt]; + encode(data, dest + to_cnt++); + } } static unsigned long *putsec(int disk, unsigned long *raw, int cnt) @@ -904,15 +904,15 @@ static void amiga_write(int disk) struct dos_header { -unsigned char track, /* 0-80 */ - side, /* 0-1 */ - sec, /* 0-...*/ - len_desc;/* 2 */ -unsigned short crc; /* on 68000 we got an alignment problem, - but this compiler solves it by adding silently - adding a pad byte so data won't fit - and this took about 3h to discover.... */ -unsigned char gap1[22]; /* for longword-alignedness (0x4e) */ + unsigned char track, /* 0-80 */ + side, /* 0-1 */ + sec, /* 0-...*/ + len_desc;/* 2 */ + unsigned short crc; /* on 68000 we got an alignment problem, + but this compiler solves it by adding silently + adding a pad byte so data won't fit + and this took about 3h to discover.... */ + unsigned char gap1[22]; /* for longword-alignedness (0x4e) */ }; /* crc routines are borrowed from the messydos-handler */ @@ -972,299 +972,308 @@ my only works was to code this from manx to C.... static ushort dos_crc(void * data_a3, int data_d0, int data_d1, int data_d3) { -static unsigned char CRCTable1[] = { - 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1, - 0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3, - 0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5, - 0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7, - 0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9, - 0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab, - 0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d, - 0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f, - 0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60, - 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72, - 0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44, - 0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56, - 0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28, - 0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a, - 0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c, - 0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e -}; - -static unsigned char CRCTable2[] = { - 0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef, - 0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde, - 0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d, - 0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc, - 0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b, - 0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a, - 0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49, - 0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78, - 0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67, - 0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56, - 0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05, - 0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34, - 0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3, - 0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92, - 0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1, - 0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0 -}; + static unsigned char CRCTable1[] = { + 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1, + 0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3, + 0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5, + 0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7, + 0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9, + 0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab, + 0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d, + 0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f, + 0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60, + 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72, + 0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44, + 0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56, + 0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28, + 0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a, + 0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c, + 0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e + }; + + static unsigned char CRCTable2[] = { + 0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef, + 0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde, + 0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d, + 0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc, + 0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b, + 0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a, + 0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49, + 0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78, + 0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67, + 0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56, + 0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05, + 0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34, + 0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3, + 0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92, + 0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1, + 0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0 + }; /* look at the asm-code - what looks in C a bit strange is almost as good as handmade */ -register int i; -register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl; - -CRCT1=CRCTable1; -CRCT2=CRCTable2; -data=data_a3; -crcl=data_d1; -crch=data_d0; -for (i=data_d3; i>=0; i--) { - c = (*data++) ^ crch; - crch = CRCT1[c] ^ crcl; - crcl = CRCT2[c]; -} -return (crch<<8)|crcl; + register int i; + register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl; + + CRCT1=CRCTable1; + CRCT2=CRCTable2; + data=data_a3; + crcl=data_d1; + crch=data_d0; + for (i=data_d3; i>=0; i--) { + c = (*data++) ^ crch; + crch = CRCT1[c] ^ crcl; + crcl = CRCT2[c]; + } + return (crch<<8)|crcl; } static inline ushort dos_hdr_crc (struct dos_header *hdr) { -return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */ + return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */ } static inline ushort dos_data_crc(unsigned char *data) { -return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */ + return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */ } static inline unsigned char dos_decode_byte(ushort word) { -register ushort w2; -register unsigned char byte; -register unsigned char *dec = mfmdecode; - -w2=word; -w2>>=8; -w2&=127; -byte = dec[w2]; -byte <<= 4; -w2 = word & 127; -byte |= dec[w2]; -return byte; + register ushort w2; + register unsigned char byte; + register unsigned char *dec = mfmdecode; + + w2=word; + w2>>=8; + w2&=127; + byte = dec[w2]; + byte <<= 4; + w2 = word & 127; + byte |= dec[w2]; + return byte; } static unsigned long dos_decode(unsigned char *data, unsigned short *raw, int len) { -int i; + int i; -for (i = 0; i < len; i++) - *data++=dos_decode_byte(*raw++); -return ((ulong)raw); + for (i = 0; i < len; i++) + *data++=dos_decode_byte(*raw++); + return ((ulong)raw); } #ifdef DEBUG static void dbg(unsigned long ptr) { - printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n",ptr, - ((ulong *)ptr)[0],((ulong *)ptr)[1],((ulong *)ptr)[2],((ulong *)ptr)[3]); + printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n", ptr, + ((ulong *)ptr)[0], ((ulong *)ptr)[1], + ((ulong *)ptr)[2], ((ulong *)ptr)[3]); } #endif static int dos_read(int drive) { - unsigned long end; - unsigned long raw; - int scnt; - unsigned short crc,data_crc[2]; - struct dos_header hdr; - - drive&=3; - raw = (long) raw_buf; - end = raw + unit[drive].type->read_size; - - for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) { - do { /* search for the right sync of each sec-hdr */ - if (!(raw = scan_sync (raw, end))) { - printk(KERN_INFO "dos_read: no hdr sync on track %d, unit %d for sector %d\n", - unit[drive].track,drive,scnt); - return MFM_NOSYNC; - } + unsigned long end; + unsigned long raw; + int scnt; + unsigned short crc,data_crc[2]; + struct dos_header hdr; + + drive&=3; + raw = (long) raw_buf; + end = raw + unit[drive].type->read_size; + + for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) { + do { /* search for the right sync of each sec-hdr */ + if (!(raw = scan_sync (raw, end))) { + printk(KERN_INFO "dos_read: no hdr sync on " + "track %d, unit %d for sector %d\n", + unit[drive].track,drive,scnt); + return MFM_NOSYNC; + } #ifdef DEBUG - dbg(raw); + dbg(raw); #endif - } while (*((ushort *)raw)!=0x5554); /* loop usually only once done */ - raw+=2; /* skip over headermark */ - raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8); - crc = dos_hdr_crc(&hdr); + } while (*((ushort *)raw)!=0x5554); /* loop usually only once done */ + raw+=2; /* skip over headermark */ + raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8); + crc = dos_hdr_crc(&hdr); #ifdef DEBUG - printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side, - hdr.sec, hdr.len_desc, hdr.crc); + printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side, + hdr.sec, hdr.len_desc, hdr.crc); #endif - if (crc != hdr.crc) { - printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n", hdr.crc, crc); - return MFM_HEADER; - } - if (hdr.track != unit[drive].track/unit[drive].type->heads) { - printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n", hdr.track, - unit[drive].track/unit[drive].type->heads); - return MFM_TRACK; - } - - if (hdr.side != unit[drive].track%unit[drive].type->heads) { - printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n", hdr.side, - unit[drive].track%unit[drive].type->heads); - return MFM_TRACK; - } - - if (hdr.len_desc != 2) { - printk(KERN_INFO "dos_read: unknown sector len descriptor %d\n", hdr.len_desc); - return MFM_DATA; - } + if (crc != hdr.crc) { + printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n", + hdr.crc, crc); + return MFM_HEADER; + } + if (hdr.track != unit[drive].track/unit[drive].type->heads) { + printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n", + hdr.track, + unit[drive].track/unit[drive].type->heads); + return MFM_TRACK; + } + + if (hdr.side != unit[drive].track%unit[drive].type->heads) { + printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n", + hdr.side, + unit[drive].track%unit[drive].type->heads); + return MFM_TRACK; + } + + if (hdr.len_desc != 2) { + printk(KERN_INFO "dos_read: unknown sector len " + "descriptor %d\n", hdr.len_desc); + return MFM_DATA; + } #ifdef DEBUG - printk("hdr accepted\n"); + printk("hdr accepted\n"); #endif - if (!(raw = scan_sync (raw, end))) { - printk(KERN_INFO "dos_read: no data sync on track %d, unit %d for sector%d, disk sector %d\n", - unit[drive].track, drive, scnt, hdr.sec); - return MFM_NOSYNC; - } + if (!(raw = scan_sync (raw, end))) { + printk(KERN_INFO "dos_read: no data sync on track " + "%d, unit %d for sector%d, disk sector %d\n", + unit[drive].track, drive, scnt, hdr.sec); + return MFM_NOSYNC; + } #ifdef DEBUG - dbg(raw); + dbg(raw); #endif - if (*((ushort *)raw)!=0x5545) { - printk(KERN_INFO "dos_read: no data mark after sync (%d,%d,%d,%d) sc=%d\n", - hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt); - return MFM_NOSYNC; - } - - raw+=2; /* skip data mark (included in checksum) */ - raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512); - raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4); - crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512); - - if (crc != data_crc[0]) { - printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) sc=%d, %x %x\n", - hdr.track, hdr.side, hdr.sec, hdr.len_desc, - scnt,data_crc[0], crc); - printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n", - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0], - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1], - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2], - ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]); - return MFM_DATA; - } - } - return 0; + if (*((ushort *)raw)!=0x5545) { + printk(KERN_INFO "dos_read: no data mark after " + "sync (%d,%d,%d,%d) sc=%d\n", + hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt); + return MFM_NOSYNC; + } + + raw+=2; /* skip data mark (included in checksum) */ + raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512); + raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4); + crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512); + + if (crc != data_crc[0]) { + printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) " + "sc=%d, %x %x\n", hdr.track, hdr.side, + hdr.sec, hdr.len_desc, scnt,data_crc[0], crc); + printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n", + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0], + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1], + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2], + ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]); + return MFM_DATA; + } + } + return 0; } static inline ushort dos_encode_byte(unsigned char byte) { -register unsigned char *enc, b2, b1; -register ushort word; - -enc=mfmencode; -b1=byte; -b2=b1>>4; -b1&=15; -word=enc[b2] <<8 | enc [b1]; -return (word|((word&(256|64)) ? 0: 128)); + register unsigned char *enc, b2, b1; + register ushort word; + + enc=mfmencode; + b1=byte; + b2=b1>>4; + b1&=15; + word=enc[b2] <<8 | enc [b1]; + return (word|((word&(256|64)) ? 0: 128)); } static void dos_encode_block(ushort *dest, unsigned char *src, int len) { -int i; + int i; -for (i = 0; i < len; i++) { - *dest=dos_encode_byte(*src++); - *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000; - dest++; -} + for (i = 0; i < len; i++) { + *dest=dos_encode_byte(*src++); + *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000; + dest++; + } } static unsigned long *ms_putsec(int drive, unsigned long *raw, int cnt) { -static struct dos_header hdr={0,0,0,2,0, - {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}}; -int i; -static ushort crc[2]={0,0x4e4e}; + static struct dos_header hdr={0,0,0,2,0, + {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}}; + int i; + static ushort crc[2]={0,0x4e4e}; -drive&=3; + drive&=3; /* id gap 1 */ /* the MFM word before is always 9254 */ -for(i=0;i<6;i++) - *raw++=0xaaaaaaaa; + for(i=0;i<6;i++) + *raw++=0xaaaaaaaa; /* 3 sync + 1 headermark */ -*raw++=0x44894489; -*raw++=0x44895554; + *raw++=0x44894489; + *raw++=0x44895554; /* fill in the variable parts of the header */ -hdr.track=unit[drive].track/unit[drive].type->heads; -hdr.side=unit[drive].track%unit[drive].type->heads; -hdr.sec=cnt+1; -hdr.crc=dos_hdr_crc(&hdr); + hdr.track=unit[drive].track/unit[drive].type->heads; + hdr.side=unit[drive].track%unit[drive].type->heads; + hdr.sec=cnt+1; + hdr.crc=dos_hdr_crc(&hdr); /* header (without "magic") and id gap 2*/ -dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28); -raw+=14; + dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28); + raw+=14; /*id gap 3 */ -for(i=0;i<6;i++) - *raw++=0xaaaaaaaa; + for(i=0;i<6;i++) + *raw++=0xaaaaaaaa; /* 3 syncs and 1 datamark */ -*raw++=0x44894489; -*raw++=0x44895545; + *raw++=0x44894489; + *raw++=0x44895545; /* data */ -dos_encode_block((ushort *)raw,(unsigned char *)unit[drive].trackbuf+cnt*512,512); -raw+=256; + dos_encode_block((ushort *)raw, + (unsigned char *)unit[drive].trackbuf+cnt*512,512); + raw+=256; /*data crc + jd's special gap (long words :-/) */ -crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512); -dos_encode_block((ushort *) raw,(unsigned char *)crc,4); -raw+=2; + crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512); + dos_encode_block((ushort *) raw,(unsigned char *)crc,4); + raw+=2; /* data gap */ -for(i=0;i<38;i++) - *raw++=0x92549254; + for(i=0;i<38;i++) + *raw++=0x92549254; -return raw; /* wrote 652 MFM words */ + return raw; /* wrote 652 MFM words */ } static void dos_write(int disk) { -int cnt; -unsigned long raw = (unsigned long) raw_buf; -unsigned long *ptr=(unsigned long *)raw; + int cnt; + unsigned long raw = (unsigned long) raw_buf; + unsigned long *ptr=(unsigned long *)raw; -disk&=3; + disk&=3; /* really gap4 + indexgap , but we write it first and round it up */ -for (cnt=0;cnt<425;cnt++) - *ptr++=0x92549254; + for (cnt=0;cnt<425;cnt++) + *ptr++=0x92549254; /* the following is just guessed */ -if (unit[disk].type->sect_mult==2) /* check for HD-Disks */ - for(cnt=0;cnt<473;cnt++) - *ptr++=0x92549254; + if (unit[disk].type->sect_mult==2) /* check for HD-Disks */ + for(cnt=0;cnt<473;cnt++) + *ptr++=0x92549254; /* now the index marks...*/ -for (cnt=0;cnt<20;cnt++) - *ptr++=0x92549254; -for (cnt=0;cnt<6;cnt++) - *ptr++=0xaaaaaaaa; -*ptr++=0x52245224; -*ptr++=0x52245552; -for (cnt=0;cnt<20;cnt++) - *ptr++=0x92549254; + for (cnt=0;cnt<20;cnt++) + *ptr++=0x92549254; + for (cnt=0;cnt<6;cnt++) + *ptr++=0xaaaaaaaa; + *ptr++=0x52245224; + *ptr++=0x52245552; + for (cnt=0;cnt<20;cnt++) + *ptr++=0x92549254; /* sectors */ -for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++) - ptr=ms_putsec(disk,ptr,cnt); + for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++) + ptr=ms_putsec(disk,ptr,cnt); -*(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */ + *(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */ } /* @@ -1299,37 +1308,38 @@ static void flush_track_callback(unsigned long nr) static int non_int_flush_track (unsigned long nr) { -unsigned long flags; - - nr&=3; - writefromint = 0; - del_timer(&post_write_timer); - get_fdc(nr); - if (!fd_motor_on(nr)) { - writepending = 0; - rel_fdc(); - return 0; - } - save_flags(flags); - cli(); - if (writepending != 2) { - restore_flags(flags); - (*unit[nr].dtype->write_fkt)(nr); - if (!raw_write(nr)) { - printk (KERN_NOTICE "floppy disk write protected in write!\n"); - writepending = 0; - return 0; - } - while (block_flag == 2) - sleep_on (&wait_fd_block); - } - else { - restore_flags(flags); - ms_delay(2); /* 2 ms post_write delay */ - post_write(nr); - } - rel_fdc(); - return 1; + unsigned long flags; + + nr&=3; + writefromint = 0; + del_timer(&post_write_timer); + get_fdc(nr); + if (!fd_motor_on(nr)) { + writepending = 0; + rel_fdc(); + return 0; + } + save_flags(flags); + cli(); + if (writepending != 2) { + restore_flags(flags); + (*unit[nr].dtype->write_fkt)(nr); + if (!raw_write(nr)) { + printk (KERN_NOTICE "floppy disk write protected " + "in write!\n"); + writepending = 0; + return 0; + } + while (block_flag == 2) + sleep_on (&wait_fd_block); + } + else { + restore_flags(flags); + ms_delay(2); /* 2 ms post_write delay */ + post_write(nr); + } + rel_fdc(); + return 1; } static int get_track(int drive, int track) @@ -1379,7 +1389,7 @@ static void redo_fd_request(void) return; } - repeat: + repeat: if (!CURRENT) { /* Nothing left to do */ return; @@ -1406,11 +1416,12 @@ static void redo_fd_request(void) floppy = unit + drive; } - /* Here someone could investigate to be more efficient */ + /* Here someone could investigate to be more efficient */ for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { #ifdef DEBUG - printk("fd: sector %ld + %d requested for %s\n",CURRENT->sector,cnt, - (CURRENT->cmd==READ)?"read":"write"); + printk("fd: sector %ld + %d requested for %s\n", + CURRENT->sector,cnt, + (CURRENT->cmd==READ)?"read":"write"); #endif block = CURRENT->sector + cnt; if ((int)block > floppy->blocks) { @@ -1422,8 +1433,8 @@ static void redo_fd_request(void) sector = block % (floppy->dtype->sects * floppy->type->sect_mult); data = CURRENT->buffer + 512 * cnt; #ifdef DEBUG - printk("access to track %d, sector %d, with buffer at 0x%08lx\n", - track, sector, data); + printk("access to track %d, sector %d, with buffer at " + "0x%08lx\n", track, sector, data); #endif if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) { @@ -1437,11 +1448,11 @@ static void redo_fd_request(void) } switch (CURRENT->cmd) { - case READ: + case READ: memcpy(data, unit[drive].trackbuf + sector * 512, 512); break; - case WRITE: + case WRITE: memcpy(unit[drive].trackbuf + sector * 512, data, 512); /* keep the drive spinning while writes are scheduled */ @@ -1494,7 +1505,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, loc.cylinders = unit[drive].type->tracks; loc.start = 0; if (copy_to_user((void *)param, (void *)&loc, - sizeof(struct hd_geometry))) + sizeof(struct hd_geometry))) return -EFAULT; break; } @@ -1545,10 +1556,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp, getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult; getprm.size=unit[drive].blocks; if (copy_to_user((void *)param, - (void *)&getprm, - sizeof(struct floppy_struct))) + (void *)&getprm, + sizeof(struct floppy_struct))) return -EFAULT; - break; + break; case BLKGETSIZE: return put_user(unit[drive].blocks,(long *)param); break; @@ -1562,13 +1573,14 @@ static int fd_ioctl(struct inode *inode, struct file *filp, #ifdef RAW_IOCTL case IOCTL_RAW_TRACK: if (copy_to_user((void *)param, raw_buf, - unit[drive].type->read_size)) + unit[drive].type->read_size)) return -EFAULT; else return unit[drive].type->read_size; #endif default: - printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",cmd,drive); + printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.", + cmd, drive); return -ENOSYS; } return 0; @@ -1589,8 +1601,8 @@ static void fd_probe(int dev) break; if (type >= num_dr_types) { - printk(KERN_WARNING "fd_probe: unsupported drive type %08lx found\n", - code); + printk(KERN_WARNING "fd_probe: unsupported drive type " + "%08lx found\n", code); unit[drive].type = &drive_types[num_dr_types-1]; /* FD_NODRIVE */ return; } @@ -1611,93 +1623,93 @@ static void fd_probe(int dev) */ static int floppy_open(struct inode *inode, struct file *filp) { - int drive; - int old_dev; - int system; - unsigned long flags; - - drive = MINOR(inode->i_rdev) & 3; - old_dev = fd_device[drive]; - - if (fd_ref[drive]) - if (old_dev != inode->i_rdev) - return -EBUSY; - - if (unit[drive].type->code == FD_NODRIVE) - return -ENODEV; - - if (filp && filp->f_mode & 3) { - check_disk_change(inode->i_rdev); - if (filp->f_mode & 2 ) { - int wrprot; - - get_fdc(drive); - fd_select (drive); - wrprot = !(ciaa.pra & DSKPROT); - fd_deselect (drive); - rel_fdc(); - - if (wrprot) - return -EROFS; - } - } - - save_flags(flags); - cli(); - fd_ref[drive]++; - fd_device[drive] = inode->i_rdev; + int drive; + int old_dev; + int system; + unsigned long flags; + + drive = MINOR(inode->i_rdev) & 3; + old_dev = fd_device[drive]; + + if (fd_ref[drive]) + if (old_dev != inode->i_rdev) + return -EBUSY; + + if (unit[drive].type->code == FD_NODRIVE) + return -ENODEV; + + if (filp && filp->f_mode & 3) { + check_disk_change(inode->i_rdev); + if (filp->f_mode & 2 ) { + int wrprot; + + get_fdc(drive); + fd_select (drive); + wrprot = !(ciaa.pra & DSKPROT); + fd_deselect (drive); + rel_fdc(); + + if (wrprot) + return -EROFS; + } + } + + save_flags(flags); + cli(); + fd_ref[drive]++; + fd_device[drive] = inode->i_rdev; #ifdef MODULE - if (unit[drive].motor == 0) - MOD_INC_USE_COUNT; + if (unit[drive].motor == 0) + MOD_INC_USE_COUNT; #endif - restore_flags(flags); + restore_flags(flags); - if (old_dev && old_dev != inode->i_rdev) - invalidate_buffers(old_dev); + if (old_dev && old_dev != inode->i_rdev) + invalidate_buffers(old_dev); - system=(inode->i_rdev & 4)>>2; - unit[drive].dtype=&data_types[system]; - unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* + system=(inode->i_rdev & 4)>>2; + unit[drive].dtype=&data_types[system]; + unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* data_types[system].sects*unit[drive].type->sect_mult; - floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1; + floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1; - printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive, - unit[drive].type->name, data_types[system].name); + printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive, + unit[drive].type->name, data_types[system].name); - return 0; + return 0; } static int floppy_release(struct inode * inode, struct file * filp) { #ifdef DEBUG - struct super_block * sb; + struct super_block * sb; #endif - int drive = MINOR(inode->i_rdev) & 3; + int drive = MINOR(inode->i_rdev) & 3; - fsync_dev(inode->i_rdev); + fsync_dev(inode->i_rdev); #ifdef DEBUG - /* This is now handled in floppy_change, but still useful for debugging */ - sb = get_super(inode->i_rdev); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(inode->i_rdev); + /* This is now handled in floppy_change, but still useful for debugging */ + sb = get_super(inode->i_rdev); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(inode->i_rdev); #endif - if (unit[drive].dirty == 1) { - del_timer (flush_track_timer + drive); - non_int_flush_track (drive); - } + if (unit[drive].dirty == 1) { + del_timer (flush_track_timer + drive); + non_int_flush_track (drive); + } - if (!fd_ref[drive]--) { - printk(KERN_CRIT "floppy_release with fd_ref == 0"); - fd_ref[drive] = 0; - } + if (!fd_ref[drive]--) { + printk(KERN_CRIT "floppy_release with fd_ref == 0"); + fd_ref[drive] = 0; + } #ifdef MODULE /* the mod_use counter is handled this way */ - floppy_off (drive | 0x40000000); + floppy_off (drive | 0x40000000); #endif - return 0; + return 0; } /* @@ -1769,23 +1781,23 @@ static int __init fd_probe_drives(void) drives=0; nomem=0; for(drive=0;drive<FD_MAX_UNITS;drive++) { - fd_probe(drive); - if (unit[drive].type->code != FD_NODRIVE) { - drives++; - if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { - printk("no mem for "); - unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ - drives--; - nomem = 1; - } - printk("fd%d ",drive); - } + fd_probe(drive); + if (unit[drive].type->code != FD_NODRIVE) { + drives++; + if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { + printk("no mem for "); + unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ + drives--; + nomem = 1; + } + printk("fd%d ",drive); + } } if ((drives > 0) || (nomem == 0)) { - if (drives == 0) - printk("no drives"); - printk("\n"); - return drives; + if (drives == 0) + printk("no drives"); + printk("\n"); + return drives; } printk("\n"); return -ENOMEM; @@ -1793,85 +1805,87 @@ static int __init fd_probe_drives(void) int __init amiga_floppy_init(void) { - int i; - - if (!AMIGAHW_PRESENT(AMI_FLOPPY)) - return -ENXIO; - if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { - printk("fd: Unable to get major %d for floppy\n",MAJOR_NR); - return -EBUSY; - } - if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE)) == NULL) { - printk("fd: cannot get chip mem buffer\n"); - unregister_blkdev(MAJOR_NR,"fd"); - return -ENOMEM; - } - - if (request_irq(IRQ_FLOPPY, fd_block_done, 0, "floppy_dma", NULL) != 0) { - printk("fd: cannot get irq for dma\n"); - amiga_chip_free(raw_buf); - unregister_blkdev(MAJOR_NR,"fd"); - return -EBUSY; - } - if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL) != 0) { - printk("fd: cannot get irq for timer\n"); - free_irq(IRQ_FLOPPY, NULL); - amiga_chip_free(raw_buf); - unregister_blkdev(MAJOR_NR,"fd"); - return -EBUSY; - } - if (fd_probe_drives() < 1) { /* No usable drives */ - free_irq(IRQ_AMIGA_CIAA_TB, NULL); - free_irq(IRQ_FLOPPY, NULL); - amiga_chip_free(raw_buf); - unregister_blkdev(MAJOR_NR,"fd"); - return -ENXIO; - } - - /* initialize variables */ - motor_on_timer.next = NULL; - motor_on_timer.prev = NULL; - motor_on_timer.expires = 0; - motor_on_timer.data = 0; - motor_on_timer.function = motor_on_callback; - for (i = 0; i < FD_MAX_UNITS; i++) { - motor_off_timer[i].next = NULL; - motor_off_timer[i].prev = NULL; - motor_off_timer[i].expires = 0; - motor_off_timer[i].data = i|0x80000000; - motor_off_timer[i].function = fd_motor_off; - flush_track_timer[i].next = NULL; - flush_track_timer[i].prev = NULL; - flush_track_timer[i].expires = 0; - flush_track_timer[i].data = i; - flush_track_timer[i].function = flush_track_callback; - - unit[i].track = -1; - } - - post_write_timer.next = NULL; - post_write_timer.prev = NULL; - post_write_timer.expires = 0; - post_write_timer.data = 0; - post_write_timer.function = post_write; + int i; + + if (!AMIGAHW_PRESENT(AMI_FLOPPY)) + return -ENXIO; + + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { + printk("fd: Unable to get major %d for floppy\n",MAJOR_NR); + return -EBUSY; + } + + if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE)) == NULL) { + printk("fd: cannot get chip mem buffer\n"); + unregister_blkdev(MAJOR_NR,"fd"); + return -ENOMEM; + } + + if (!request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) { + printk("fd: cannot get irq for dma\n"); + amiga_chip_free(raw_buf); + unregister_blkdev(MAJOR_NR,"fd"); + return -EBUSY; + } + if (!request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) { + printk("fd: cannot get irq for timer\n"); + free_irq(IRQ_AMIGA_DSKBLK, NULL); + amiga_chip_free(raw_buf); + unregister_blkdev(MAJOR_NR,"fd"); + return -EBUSY; + } + if (fd_probe_drives() < 1) { /* No usable drives */ + free_irq(IRQ_AMIGA_CIAA_TB, NULL); + free_irq(IRQ_AMIGA_DSKBLK, NULL); + amiga_chip_free(raw_buf); + unregister_blkdev(MAJOR_NR,"fd"); + return -ENXIO; + } + + /* initialize variables */ + motor_on_timer.next = NULL; + motor_on_timer.prev = NULL; + motor_on_timer.expires = 0; + motor_on_timer.data = 0; + motor_on_timer.function = motor_on_callback; + for (i = 0; i < FD_MAX_UNITS; i++) { + motor_off_timer[i].next = NULL; + motor_off_timer[i].prev = NULL; + motor_off_timer[i].expires = 0; + motor_off_timer[i].data = i|0x80000000; + motor_off_timer[i].function = fd_motor_off; + flush_track_timer[i].next = NULL; + flush_track_timer[i].prev = NULL; + flush_track_timer[i].expires = 0; + flush_track_timer[i].data = i; + flush_track_timer[i].function = flush_track_callback; + + unit[i].track = -1; + } + + post_write_timer.next = NULL; + post_write_timer.prev = NULL; + post_write_timer.expires = 0; + post_write_timer.data = 0; + post_write_timer.function = post_write; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_size[MAJOR_NR] = floppy_sizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; - for (i = 0; i < 128; i++) - mfmdecode[i]=255; - for (i = 0; i < 16; i++) - mfmdecode[mfmencode[i]]=i; + for (i = 0; i < 128; i++) + mfmdecode[i]=255; + for (i = 0; i < 16; i++) + mfmdecode[mfmencode[i]]=i; - /* make sure that disk DMA is enabled */ - custom.dmacon = DMAF_SETCLR | DMAF_DISK; + /* make sure that disk DMA is enabled */ + custom.dmacon = DMAF_SETCLR | DMAF_DISK; - /* init ms timer */ - ciaa.crb = 8; /* one-shot, stop */ + /* init ms timer */ + ciaa.crb = 8; /* one-shot, stop */ - (void)do_floppy; /* avoid warning about unused variable */ - return 0; + (void)do_floppy; /* avoid warning about unused variable */ + return 0; } #ifdef MODULE @@ -1879,25 +1893,25 @@ int __init amiga_floppy_init(void) int init_module(void) { - if (!MACH_IS_AMIGA) - return -ENXIO; - return amiga_floppy_init(); + if (!MACH_IS_AMIGA) + return -ENXIO; + return amiga_floppy_init(); } void cleanup_module(void) { -int i; - -for( i = 0; i < FD_MAX_UNITS; i++) - if (unit[i].type->code != FD_NODRIVE) - kfree(unit[i].trackbuf); -free_irq(IRQ_AMIGA_CIAA_TB, NULL); -free_irq(IRQ_FLOPPY, NULL); -custom.dmacon = DMAF_DISK; /* disable DMA */ -amiga_chip_free(raw_buf); -blk_size[MAJOR_NR] = NULL; -blksize_size[MAJOR_NR] = NULL; -blk_dev[MAJOR_NR].request_fn = NULL; -unregister_blkdev(MAJOR_NR, "fd"); + int i; + + for( i = 0; i < FD_MAX_UNITS; i++) + if (unit[i].type->code != FD_NODRIVE) + kfree(unit[i].trackbuf); + free_irq(IRQ_AMIGA_CIAA_TB, NULL); + free_irq(IRQ_AMIGA_DSKBLK, NULL); + custom.dmacon = DMAF_DISK; /* disable DMA */ + amiga_chip_free(raw_buf); + blk_size[MAJOR_NR] = NULL; + blksize_size[MAJOR_NR] = NULL; + blk_dev[MAJOR_NR].request_fn = NULL; + unregister_blkdev(MAJOR_NR, "fd"); } #endif diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index cf408b8c7..b8df87205 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -215,11 +215,10 @@ static struct atari_disk_type user_params[FD_MAX_UNITS]; * restored upon disk change by floppy_revalidate() if valid (as seen by * default_params[].blocks > 0 - a bit in unit[].flags might be used for this?) */ -static struct atari_disk_type default_params[FD_MAX_UNITS] = { - { NULL, 0, 0, 0, 0}, }; +static struct atari_disk_type default_params[FD_MAX_UNITS]; static int floppy_sizes[256]; -static int floppy_blocksizes[256] = { 0, }; +static int floppy_blocksizes[256]; /* current info on each unit */ static struct atari_floppy_struct { @@ -331,26 +330,6 @@ static unsigned int changed_floppies = 0xff, fake_change = 0; * will give up. */ -#define START_MOTOR_OFF_TIMER(delay) \ - do { \ - motor_off_timer.expires = jiffies + (delay); \ - add_timer( &motor_off_timer ); \ - MotorOffTrys = 0; \ - } while(0) - -#define START_CHECK_CHANGE_TIMER(delay) \ - do { \ - timer_table[FLOPPY_TIMER].expires = jiffies + (delay); \ - timer_active |= (1 << FLOPPY_TIMER); \ - } while(0) - -#define START_TIMEOUT() \ - mod_timer(&timeout_timer, jiffies + FLOPPY_TIMEOUT) - -#define STOP_TIMEOUT() \ - del_timer(&timeout_timer) - - /* * The driver is trying to determine the correct media format * while Probing is set. fd_rwsec_done() clears it after a @@ -420,6 +399,31 @@ static struct timer_list timeout_timer = { NULL, NULL, 0, 0, fd_times_out }; +static inline void +start_motor_off_timer(void) +{ + mod_timer(&motor_off_timer, jiffies + FD_MOTOR_OFF_DELAY); + MotorOffTrys = 0; +} + +static inline void +start_check_change_timer(void) +{ + timer_table[FLOPPY_TIMER].expires = jiffies + CHECK_CHANGE_DELAY; + timer_active |= (1 << FLOPPY_TIMER); +} + +static inline void +start_timeout(void) +{ + mod_timer(&timeout_timer, jiffies + FLOPPY_TIMEOUT); +} + +static inline void +stop_timeout(void) +{ + del_timer(&timeout_timer); +} /* Select the side to use. */ @@ -497,19 +501,12 @@ static void fd_deselect( void ) static void fd_motor_off_timer( unsigned long dummy ) { -/* unsigned long flags; */ unsigned char status; - int delay; - del_timer( &motor_off_timer ); - if (SelectedDrive < 0) /* no drive selected, needn't deselect anyone */ return; -/* save_flags(flags); - cli(); */ - if (stdma_islocked()) goto retry; @@ -519,21 +516,18 @@ static void fd_motor_off_timer( unsigned long dummy ) /* motor already turned off by FDC -> deselect drives */ MotorOn = 0; fd_deselect(); -/* restore_flags(flags); */ return; } /* not yet off, try again */ retry: -/* restore_flags(flags); */ /* Test again later; if tested too often, it seems there is no disk * in the drive and the FDC will leave the motor on forever (or, * at least until a disk is inserted). So we'll test only twice * per second from then on... */ - delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ? - (++MotorOffTrys, HZ/20) : HZ/2; - START_MOTOR_OFF_TIMER( delay ); + mod_timer(&motor_off_timer, + jiffies + (MotorOffTrys++ < FD_MOTOR_OFF_MAXTRY ? HZ/20 : HZ/2)); } @@ -571,7 +565,7 @@ static void check_change( void ) } restore_flags(flags); - START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); + start_check_change_timer(); } @@ -603,8 +597,7 @@ static void floppy_irq (int irq, void *dummy, struct pt_regs *fp) unsigned char status; void (*handler)( int ); - handler = FloppyIRQHandler; - FloppyIRQHandler = NULL; + handler = xchg(&FloppyIRQHandler, NULL); if (handler) { nop(); @@ -805,7 +798,7 @@ static void fd_calibrate( void ) NeedSeek = 1; MotorOn = 1; - START_TIMEOUT(); + start_timeout(); /* wait for IRQ */ } @@ -813,7 +806,7 @@ static void fd_calibrate( void ) static void fd_calibrate_done( int status ) { DPRINT(("fd_calibrate_done()\n")); - STOP_TIMEOUT(); + stop_timeout(); /* set the correct speed now */ if (ATARIHW_PRESENT(FDCSPEED)) @@ -853,7 +846,7 @@ static void fd_seek( void ) MotorOn = 1; set_head_settle_flag(); - START_TIMEOUT(); + start_timeout(); /* wait for IRQ */ } @@ -861,7 +854,7 @@ static void fd_seek( void ) static void fd_seek_done( int status ) { DPRINT(("fd_seek_done()\n")); - STOP_TIMEOUT(); + stop_timeout(); /* set the correct speed */ if (ATARIHW_PRESENT(FDCSPEED)) @@ -900,7 +893,7 @@ static void fd_rwsec( void ) DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n",ReqSector, ReqCmd == WRITE ? 'w' : 'r' )); if (ReqCmd == WRITE) { if (ATARIHW_PRESENT(EXTD_DMA)) { - paddr = (unsigned long)VTOP(ReqData); + paddr = virt_to_phys(ReqData); } else { copy_buffer( ReqData, DMABuffer ); @@ -913,7 +906,8 @@ static void fd_rwsec( void ) if (read_track) paddr = PhysTrackBuffer; else - paddr = ATARIHW_PRESENT(EXTD_DMA) ? VTOP(ReqData) : PhysDMABuffer; + paddr = ATARIHW_PRESENT(EXTD_DMA) ? + virt_to_phys(ReqData) : PhysDMABuffer; rwflag = 0; } @@ -978,14 +972,12 @@ static void fd_rwsec( void ) * search for the first non-existent sector and need 1 sec to * recognise that it isn't present :-( */ - del_timer (&readtrack_timer); - readtrack_timer.expires = - jiffies + HZ/5 + (old_motoron ? 0 : HZ); - /* 1 rot. + 5 rot.s if motor was off */ MultReadInProgress = 1; - add_timer( &readtrack_timer ); + mod_timer(&readtrack_timer, + /* 1 rot. + 5 rot.s if motor was off */ + jiffies + HZ/5 + (old_motoron ? 0 : HZ)); } - START_TIMEOUT(); + start_timeout(); } @@ -996,8 +988,6 @@ static void fd_readtrack_check( unsigned long dummy ) save_flags(flags); cli(); - del_timer( &readtrack_timer ); - if (!MultReadInProgress) { /* This prevents a race condition that could arise if the * interrupt is triggered while the calling of this timer @@ -1045,8 +1035,7 @@ static void fd_readtrack_check( unsigned long dummy ) /* not yet finished, wait another tenth rotation */ restore_flags(flags); DPRINT(("fd_readtrack_check(): not yet finished\n")); - readtrack_timer.expires = jiffies + HZ/5/10; - add_timer( &readtrack_timer ); + mod_timer(&readtrack_timer, jiffies + HZ/5/10); } } @@ -1068,7 +1057,7 @@ static void fd_rwsec_done1(int status) { unsigned int track; - STOP_TIMEOUT(); + stop_timeout(); /* Correct the track if stretch != 0 */ if (SUDT->stretch) { @@ -1150,7 +1139,7 @@ static void fd_rwsec_done1(int status) if (!read_track) { void *addr; addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer; - dma_cache_maintenance( VTOP(addr), 512, 0 ); + dma_cache_maintenance( virt_to_phys(addr), 512, 0 ); if (!ATARIHW_PRESENT( EXTD_DMA )) copy_buffer (addr, ReqData); } else { @@ -1237,7 +1226,7 @@ static void fd_writetrack( void ) dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag(); MotorOn = 1; - START_TIMEOUT(); + start_timeout(); /* wait for interrupt */ } @@ -1246,7 +1235,7 @@ static void fd_writetrack_done( int status ) { DPRINT(("fd_writetrack_done()\n")); - STOP_TIMEOUT(); + stop_timeout(); if (status & FDCSTAT_WPROT) { printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive ); @@ -1304,7 +1293,7 @@ static void finish_fdc( void ) SET_IRQ_HANDLER( finish_fdc_done ); FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK); MotorOn = 1; - START_TIMEOUT(); + start_timeout(); /* we must wait for the IRQ here, because the ST-DMA is released immediately afterwards and the interrupt may be delivered to the wrong driver. */ @@ -1317,19 +1306,18 @@ static void finish_fdc_done( int dummy ) unsigned long flags; DPRINT(("finish_fdc_done entered\n")); - STOP_TIMEOUT(); + stop_timeout(); NeedSeek = 0; if ((timer_active & (1 << FLOPPY_TIMER)) && - timer_table[FLOPPY_TIMER].expires < jiffies + 5) + time_before(timer_table[FLOPPY_TIMER].expires, jiffies + 5)) /* If the check for a disk change is done too early after this * last seek command, the WP bit still reads wrong :-(( */ timer_table[FLOPPY_TIMER].expires = jiffies + 5; else - START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); - del_timer( &motor_off_timer ); - START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY ); + start_check_change_timer(); + start_motor_off_timer(); save_flags(flags); cli(); @@ -1828,10 +1816,10 @@ static int __init fd_test_drive_present( int drive ) FDC_WRITE (FDCREG_TRACK, 0xff00); FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 ); - for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; time_before(jiffies, timeout); ) { + timeout = jiffies + 2*HZ+HZ/2; + while (time_before(jiffies, timeout)) if (!(mfp.par_dt_reg & 0x20)) break; - } status = FDC_READ( FDCREG_STATUS ); ok = (status & FDCSTAT_TR00) != 0; @@ -1892,9 +1880,9 @@ static void __init config_types( void ) } if (cnt > 0) { - START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY ); + start_motor_off_timer(); if (cnt == 1) fd_select_drive( 0 ); - START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); + start_check_change_timer(); } } @@ -2045,8 +2033,8 @@ int __init atari_floppy_init (void) return -ENOMEM; } TrackBuffer = DMABuffer + 512; - PhysDMABuffer = (unsigned long) VTOP(DMABuffer); - PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer); + PhysDMABuffer = virt_to_phys(DMABuffer); + PhysTrackBuffer = virt_to_phys(TrackBuffer); BufferDrive = BufferSide = BufferTrack = -1; for (i = 0; i < FD_MAX_UNITS; i++) { diff --git a/drivers/block/cmd646.c b/drivers/block/cmd646.c index 52e572507..05cf7c2bf 100644 --- a/drivers/block/cmd646.c +++ b/drivers/block/cmd646.c @@ -1,4 +1,4 @@ -/* $Id: cmd646.c,v 1.14 1999/07/03 08:56:09 davem Exp $ +/* $Id: cmd646.c,v 1.15 1999/07/23 01:48:37 davem Exp $ * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because * there the "BIOS" has done all of the following already. diff --git a/drivers/block/cmos-probe.c b/drivers/block/cmos-probe.c new file mode 100644 index 000000000..f0147d5e3 --- /dev/null +++ b/drivers/block/cmos-probe.c @@ -0,0 +1,78 @@ +/* + * linux/drivers/block/cmos-probe.c Version 1.00 August 16, 1999 + * + * Copyright (C) 1994-1999 Linus Torvalds & authors (see below) + */ + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/major.h> +#include <linux/errno.h> +#include <linux/genhd.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/ide.h> + + +#include <asm/byteorder.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +/* + * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc + * controller that is BIOS compatible with ST-506, and thus showing up in our + * BIOS table, but not register compatible, and therefore not present in CMOS. + * + * Furthermore, we will assume that our ST-506 drives <if any> are the primary + * drives in the system -- the ones reflected as drive 1 or 2. The first + * drive is stored in the high nibble of CMOS byte 0x12, the second in the low + * nibble. This will be either a 4 bit drive type or 0xf indicating use byte + * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value + * means we have an AT controller hard disk for that drive. + * + * Of course, there is no guarantee that either drive is actually on the + * "primary" IDE interface, but we don't bother trying to sort that out here. + * If a drive is not actually on the primary interface, then these parameters + * will be ignored. This results in the user having to supply the logical + * drive geometry as a boot parameter for each drive not on the primary i/f. + * + * The only "perfect" way to handle this would be to modify the setup.[cS] code + * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info + * for us during initialization. I have the necessary docs -- any takers? -ml + */ +void probe_cmos_for_drives (ide_hwif_t *hwif) +{ +#ifdef __i386__ + extern struct drive_info_struct drive_info; + byte cmos_disks, *BIOS = (byte *) &drive_info; + int unit; + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) + return; +#endif /* CONFIG_BLK_DEV_PDC4030 */ + outb_p(0x12,0x70); /* specify CMOS address 0x12 */ + cmos_disks = inb_p(0x71); /* read the data from 0x12 */ + /* Extract drive geometry from CMOS+BIOS if not already setup */ + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) { + drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; + drive->head = drive->bios_head = *(BIOS+2); + drive->sect = drive->bios_sect = *(BIOS+14); + drive->ctl = *(BIOS+8); + drive->present = 1; + } + BIOS += 16; + } +#endif +} diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 7aeff3bfb..1b2be20dd 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -35,8 +35,8 @@ #include <linux/timer.h> #include <linux/proc_fs.h> #include <linux/hdreg.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> -#include <asm/spinlock.h> #include <asm/io.h> @@ -631,7 +631,7 @@ static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) irq = pdev->irq; for(i=0; i<6; i++) - addr[i] = pdev->base_address[i]; + addr[i] = pdev->resource[i].flags; (void) pcibios_read_config_word(bus, device_fn, PCI_COMMAND,&command); @@ -665,7 +665,7 @@ DBGINFO( */ for(i=0; i<6; i++) if (!(addr[i] & 0x1)) { - c->paddr = addr[i]; + c->paddr = pdev->resource[i].start; break; } c->vaddr = remap_pci_mem(c->paddr, 128); diff --git a/drivers/block/cy82c693.c b/drivers/block/cy82c693.c index e1e46ea8a..e204bc0e6 100644 --- a/drivers/block/cy82c693.c +++ b/drivers/block/cy82c693.c @@ -369,6 +369,17 @@ static void cy82c693_tune_drive (ide_drive_t *drive, byte pio) /* * this function is called during init and is used to setup the cy82c693 chip */ +/* + * FIXME! "pci_init_cy82c693" really should replace + * the "init_cy82c693_chip", it is the correct location to tinker/setup + * the device prior to INIT. + */ + +unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name) +{ + return 0; +} + static void init_cy82c693_chip (struct pci_dev *dev) { static int initDone = 0; @@ -420,7 +431,7 @@ static void init_cy82c693_chip (struct pci_dev *dev) /* * the init function - called for each ide channel once */ -__initfunc(void ide_init_cy82c693(ide_hwif_t *hwif)) +void __init ide_init_cy82c693(ide_hwif_t *hwif) { hwif->chipset = ide_cy82c693; if (hwif->dma_base) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index ae2ab6b0f..d74fdc369 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -106,6 +106,12 @@ * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives. */ +/* + * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24 + * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were + * being used to store jiffies, which are unsigned longs). + */ + #define FLOPPY_SANITY_CHECK #undef FLOPPY_SILENT_DCL_CLEAR @@ -330,7 +336,6 @@ static int inr; /* size of reply buffer, when called from interrupt */ #define SEL_DLY (2*HZ/100) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* * this struct defines the different floppy drive types. */ @@ -607,10 +612,10 @@ static void is_alive(const char *message) #define OLOGSIZE 20 static void (*lasthandler)(void) = NULL; -static int interruptjiffies=0; -static int resultjiffies=0; +static unsigned long interruptjiffies=0; +static unsigned long resultjiffies=0; static int resultsize=0; -static int lastredo=0; +static unsigned long lastredo=0; static struct output_log { unsigned char data; @@ -630,7 +635,7 @@ static void reschedule_timeout(int drive, const char *message, int marg) drive = current_drive; del_timer(&fd_timeout); if (drive < 0 || drive > N_DRIVE) { - fd_timeout.expires = jiffies + 20*HZ; + fd_timeout.expires = jiffies + 20UL*HZ; drive=0; } else fd_timeout.expires = jiffies + UDP->timeout; @@ -713,7 +718,7 @@ static int disk_change(int drive) #ifdef DCL_DEBUG if (UDP->flags & FD_DEBUG){ DPRINT("checking disk change line for drive %d\n",drive); - DPRINT("jiffies=%ld\n", jiffies); + DPRINT("jiffies=%lu\n", jiffies); DPRINT("disk change line=%x\n",fd_inb(FD_DIR)&0x80); DPRINT("flags=%lx\n",UDRS->flags); } @@ -1007,7 +1012,7 @@ static void main_command_interrupt(void) } /* waits for a delay (spinup or select) to pass */ -static int wait_for_completion(int delay, timeout_fn function) +static int wait_for_completion(unsigned long delay, timeout_fn function) { if (FDCS->reset){ reset_fdc(); /* do the reset during sleep to win time @@ -1280,7 +1285,7 @@ static int fdc_configure(void) static void fdc_specify(void) { unsigned char spec1, spec2; - int srt, hlt, hut; + unsigned long srt, hlt, hut; unsigned long dtr = NOMINAL_DTR; unsigned long scale_dtr = NOMINAL_DTR; int hlt_max_code = 0x7f; @@ -1370,7 +1375,7 @@ static int fdc_dtr(void) * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) */ FDCS->dtr = raw_cmd->rate & 3; - return(wait_for_completion(jiffies+2*HZ/100, + return(wait_for_completion(jiffies+2UL*HZ/100, (timeout_fn) floppy_ready)); } /* fdc_dtr */ @@ -1466,7 +1471,8 @@ static int interpret_errors(void) */ static void setup_rw_floppy(void) { - int i,ready_date,r, flags,dflags; + int i,r, flags,dflags; + unsigned long ready_date; timeout_fn function; flags = raw_cmd->flags; @@ -1539,7 +1545,7 @@ static void seek_interrupt(void) #ifdef DCL_DEBUG if (DP->flags & FD_DEBUG){ DPRINT("clearing NEWCHANGE flag because of effective seek\n"); - DPRINT("jiffies=%ld\n", jiffies); + DPRINT("jiffies=%lu\n", jiffies); } #endif CLEARF(FD_DISK_NEWCHANGE); /* effective seek */ @@ -1829,20 +1835,20 @@ static void show_floppy(void) printk("\n"); printk("floppy driver state\n"); printk("-------------------\n"); - printk("now=%ld last interrupt=%d last called handler=%p\n", - jiffies, interruptjiffies, lasthandler); + printk("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n", + jiffies, interruptjiffies, jiffies-interruptjiffies, lasthandler); #ifdef FLOPPY_SANITY_CHECK printk("timeout_message=%s\n", timeout_message); printk("last output bytes:\n"); for (i=0; i < OLOGSIZE; i++) - printk("%2x %2x %ld\n", + printk("%2x %2x %lu\n", output_log[(i+output_log_pos) % OLOGSIZE].data, output_log[(i+output_log_pos) % OLOGSIZE].status, output_log[(i+output_log_pos) % OLOGSIZE].jiffies); - printk("last result at %d\n", resultjiffies); - printk("last redo_fd_request at %d\n", lastredo); + printk("last result at %lu\n", resultjiffies); + printk("last redo_fd_request at %lu\n", lastredo); for (i=0; i<resultsize; i++){ printk("%2x ", reply_buffer[i]); } @@ -1859,8 +1865,8 @@ static void show_floppy(void) printk("fd_timer.function=%p\n", fd_timer.function); if (fd_timeout.prev){ printk("timer_table=%p\n",fd_timeout.function); - printk("expires=%ld\n",fd_timeout.expires-jiffies); - printk("now=%ld\n",jiffies); + printk("expires=%lu\n",fd_timeout.expires-jiffies); + printk("now=%lu\n",jiffies); } printk("cont=%p\n", cont); printk("CURRENT=%p\n", CURRENT); @@ -3005,12 +3011,12 @@ static int user_reset_fdc(int drive, int arg, int interruptible) * Misc Ioctl's and support * ======================== */ -static inline int fd_copyout(void *param, const void *address, int size) +static inline int fd_copyout(void *param, const void *address, unsigned long size) { return copy_to_user(param,address, size) ? -EFAULT : 0; } -static inline int fd_copyin(void *param, void *address, int size) +static inline int fd_copyin(void *param, void *address, unsigned long size) { return copy_from_user(address, param, size) ? -EFAULT : 0; } @@ -3808,7 +3814,7 @@ static int check_floppy_change(kdev_t dev) if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY)) return 1; - if (UDP->checkfreq < jiffies - UDRS->last_checked){ + if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) { lock_fdc(drive,0); poll_drive(0,0); process_fd_request(); @@ -4064,11 +4070,13 @@ static struct param_table { { "no_unexpected_interrupts", 0, &print_unex, 0, 0 }, { "L40SX", 0, &print_unex, 0, 0 } }; -#define FLOPPY_SETUP -void __init floppy_setup(char *str, int *ints) +static int __init floppy_setup(char *str) { int i; int param; + int ints[11]; + + str = get_options(str,ARRAY_SIZE(ints),ints); if (str) { for (i=0; i< ARRAY_SIZE(config_params); i++){ if (strcmp(str,config_params[i].name) == 0){ @@ -4084,7 +4092,7 @@ void __init floppy_setup(char *str, int *ints) DPRINT("%s=%d\n", str, param); *config_params[i].var = param; } - return; + return 1; } } } @@ -4098,6 +4106,7 @@ void __init floppy_setup(char *str, int *ints) } else DPRINT("botched floppy option\n"); DPRINT("Read linux/drivers/block/README.fd\n"); + return 1; } static int have_no_fdc= -EIO; @@ -4361,14 +4370,11 @@ static void floppy_release_irq_and_dma(void) #ifdef MODULE -extern char *get_options(char *str, int *ints); - char *floppy=NULL; static void __init parse_floppy_cfg_string(char *cfg) { char *ptr; - int ints[11]; while(*cfg) { for(ptr = cfg;*cfg && *cfg != ' ' && *cfg != '\t'; cfg++); @@ -4377,18 +4383,17 @@ static void __init parse_floppy_cfg_string(char *cfg) cfg++; } if(*ptr) - floppy_setup(get_options(ptr,ints),ints); + floppy_setup(ptr); } } -static void __init mod_setup(char *pattern, void (*setup)(char *, int *)) +static void __init mod_setup(char *pattern, int (*setup)(char *)) { unsigned long i; char c; int j; int match; char buffer[100]; - int ints[11]; int length = strlen(pattern)+1; match=0; @@ -4403,7 +4408,7 @@ static void __init mod_setup(char *pattern, void (*setup)(char *, int *)) if (!c || c == ' ' || c == '\t'){ if (j){ buffer[j] = '\0'; - setup(get_options(buffer,ints),ints); + setup(buffer); } j=0; } else @@ -4461,6 +4466,9 @@ MODULE_SUPPORTED_DEVICE("fd"); #endif #else + +__setup ("floppy=", floppy_setup); + /* eject the boot floppy (if we need the drive for a different root floppy) */ /* This should only be called at boot time when we're sure that there's no * resource contention. */ diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 5f4b38559..aece0447d 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -4,1452 +4,31 @@ * * Copyright (C) 1991-1998 Linus Torvalds * - * - * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * in the early extended-partition checks and added DM partitions - * - * Support for DiskManager v6.0x added by Mark Lord, - * with information provided by OnTrack. This now works for linux fdisk - * and LILO, as well as loadlin and bootln. Note that disks other than - * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). - * - * More flexible handling of extended partitions - aeb, 950831 - * - * Check partition table on IDE disks for common CHS translations - * - * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} + * Moved partition checking code to fs/partitions* - Russell King + * (linux@arm.uk.linux.org) */ #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/init.h> -#include <asm/system.h> -#include <asm/byteorder.h> - -/* - * Many architectures don't like unaligned accesses, which is - * frequently the case with the nr_sects and start_sect partition - * table entries. - */ -#include <asm/unaligned.h> - -#define SYS_IND(p) (get_unaligned(&p->sys_ind)) -#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \ - get_unaligned(&p->nr_sects); \ - le32_to_cpu(__a); \ - }) - -#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \ - get_unaligned(&p->start_sect); \ - le32_to_cpu(__a); \ - }) - -struct gendisk *gendisk_head = NULL; - -static int current_minor = 0; -extern int *blk_size[]; -extern void rd_load(void); -extern void initrd_load(void); - +extern int parport_init(void); extern int chr_dev_init(void); extern int blk_dev_init(void); +#ifdef CONFIG_BLK_DEV_DAC960 +extern void DAC960_Initialize(void); +#endif extern int scsi_dev_init(void); extern int net_dev_init(void); -extern int i2o_init(void); - -#ifdef CONFIG_PPC -extern void note_bootable_part(kdev_t dev, int part); -#endif - -/* - * disk_name() is used by genhd.c and blkpg.c. - * 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; - const char *maj = hd->major_name; - int unit = (minor >> hd->minor_shift) + 'a'; - - /* - * IDE devices use multiple major numbers, but the drives - * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. - * This requires special handling here. - */ - switch (hd->major) { - case IDE7_MAJOR: - unit += 2; - case IDE6_MAJOR: - unit += 2; - case IDE5_MAJOR: - unit += 2; - case IDE4_MAJOR: - unit += 2; - case IDE3_MAJOR: - unit += 2; - case IDE2_MAJOR: - unit += 2; - case IDE1_MAJOR: - unit += 2; - case IDE0_MAJOR: - maj = "hd"; - break; - } - part = minor & ((1 << hd->minor_shift) - 1); - if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { - unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; - if (unit > 'z') { - unit -= 'z' + 1; - sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26); - if (part) - sprintf(buf + 4, "%d", part); - return buf; - } - } - if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) { - int ctlr = hd->major - COMPAQ_SMART2_MAJOR; - int disk = minor >> hd->minor_shift; - int part = minor & (( 1 << hd->minor_shift) - 1); - if (part == 0) - sprintf(buf, "%s/c%dd%d", maj, ctlr, disk); - else - sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part); - return buf; - } - if (part) - sprintf(buf, "%s%c%d", maj, unit, part); - else - sprintf(buf, "%s%c", maj, unit); - return buf; -} - -static void add_partition (struct gendisk *hd, int minor, int start, int size) -{ - char buf[40]; - hd->part[minor].start_sect = start; - hd->part[minor].nr_sects = size; - if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) - printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); - else - printk(" %s", disk_name(hd, minor, buf)); -} - -static inline int is_extended_partition(struct partition *p) -{ - return (SYS_IND(p) == DOS_EXTENDED_PARTITION || - SYS_IND(p) == WIN98_EXTENDED_PARTITION || - SYS_IND(p) == LINUX_EXTENDED_PARTITION); -} - -int get_hardsect_size(kdev_t dev) -{ - if (hardsect_size[MAJOR(dev)] != NULL) - return hardsect_size[MAJOR(dev)][MINOR(dev)]; - else - return 512; -} - -static unsigned int get_ptable_blocksize(kdev_t dev) -{ - int ret = 1024; - - /* - * See whether the low-level driver has given us a minumum blocksize. - * If so, check to see whether it is larger than the default of 1024. - */ - if (!blksize_size[MAJOR(dev)]) - { - return ret; - } - - /* - * Check for certain special power of two sizes that we allow. - * With anything larger than 1024, we must force the blocksize up to - * the natural blocksize for the device so that we don't have to try - * and read partial sectors. Anything smaller should be just fine. - */ - - switch( blksize_size[MAJOR(dev)][MINOR(dev)] ) - { - case 2048: - ret = 2048; - break; - case 4096: - ret = 4096; - break; - case 8192: - ret = 8192; - break; - case 1024: - case 512: - case 256: - case 0: - /* - * These are all OK. - */ - break; - default: - panic("Strange blocksize for partition table\n"); - } - - return ret; - -} - -#ifdef CONFIG_MSDOS_PARTITION -/* - * Create devices for each logical partition in an extended partition. - * The logical partitions form a linked list, with each entry being - * a partition table with two entries. The first entry - * is the real data partition (with a start relative to the partition - * table start). The second is a pointer to the next logical partition - * (with a start relative to the entire extended partition). - * We do not create a Linux partition for the partition tables, but - * only for the actual data partitions. - */ - -#define MSDOS_LABEL_MAGIC 0xAA55 - -static void extended_partition(struct gendisk *hd, kdev_t dev) -{ - struct buffer_head *bh; - struct partition *p; - unsigned long first_sector, first_size, this_sector, this_size; - int mask = (1 << hd->minor_shift) - 1; - int sector_size = get_hardsect_size(dev) / 512; - int i; - - first_sector = hd->part[MINOR(dev)].start_sect; - first_size = hd->part[MINOR(dev)].nr_sects; - this_sector = first_sector; - - while (1) { - if ((current_minor & mask) == 0) - return; - if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) - return; - - if ((*(__u16 *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC)) - goto done; - - p = (struct partition *) (0x1BE + bh->b_data); - - this_size = hd->part[MINOR(dev)].nr_sects; - - /* - * Usually, the first entry is the real data partition, - * the 2nd entry is the next extended partition, or empty, - * and the 3rd and 4th entries are unused. - * However, DRDOS sometimes has the extended partition as - * the first entry (when the data partition is empty), - * and OS/2 seems to use all four entries. - */ - - /* - * First process the data partition(s) - */ - for (i=0; i<4; i++, p++) { - if (!NR_SECTS(p) || is_extended_partition(p)) - continue; - - /* Check the 3rd and 4th entries - - these sometimes contain random garbage */ - if (i >= 2 - && START_SECT(p) + NR_SECTS(p) > this_size - && (this_sector + START_SECT(p) < first_sector || - this_sector + START_SECT(p) + NR_SECTS(p) > - first_sector + first_size)) - continue; - - add_partition(hd, current_minor, this_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size); - current_minor++; - if ((current_minor & mask) == 0) - goto done; - } - /* - * Next, process the (first) extended partition, if present. - * (So far, there seems to be no reason to make - * extended_partition() recursive and allow a tree - * of extended partitions.) - * It should be a link to the next logical partition. - * Create a minor for this just long enough to get the next - * partition table. The minor will be reused for the next - * data partition. - */ - p -= 4; - for (i=0; i<4; i++, p++) - if(NR_SECTS(p) && is_extended_partition(p)) - break; - if (i == 4) - goto done; /* nothing left to do */ - - hd->part[current_minor].nr_sects = NR_SECTS(p) * sector_size; /* JSt */ - hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size; - this_sector = first_sector + START_SECT(p) * sector_size; - dev = MKDEV(hd->major, current_minor); - - /* Use bforget(), as we have changed the disk geometry */ - bforget(bh); - } -done: - bforget(bh); -} - -#ifdef CONFIG_SOLARIS_X86_PARTITION -static void -solaris_x86_partition(struct gendisk *hd, kdev_t dev, long offset) { - - struct buffer_head *bh; - struct solaris_x86_vtoc *v; - struct solaris_x86_slice *s; - int i; - - if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) - return; - v = (struct solaris_x86_vtoc *)(bh->b_data + 512); - if(v->v_sanity != SOLARIS_X86_VTOC_SANE) { - brelse(bh); - return; - } - printk(" <solaris:"); - if(v->v_version != 1) { - printk(" cannot handle version %ld vtoc>", v->v_version); - brelse(bh); - return; - } - for(i=0; i<SOLARIS_X86_NUMSLICE; i++) { - s = &v->v_slice[i]; - - if (s->s_size == 0) - continue; - printk(" [s%d]", i); - /* solaris partitions are relative to current MS-DOS - * one but add_partition starts relative to sector - * zero of the disk. Therefore, must add the offset - * of the current partition */ - add_partition(hd, current_minor, s->s_start+offset, s->s_size); - current_minor++; - } - brelse(bh); - printk(" >"); -} -#endif - -#ifdef CONFIG_BSD_DISKLABEL -static void check_and_add_bsd_partition(struct gendisk *hd, - struct bsd_partition *bsd_p, kdev_t dev) -{ - struct hd_struct *lin_p; - /* check relative position of partitions. */ - for (lin_p = hd->part + 1 + MINOR(dev); - lin_p - hd->part - MINOR(dev) < current_minor; lin_p++) { - /* no relationship -> try again */ - if (lin_p->start_sect + lin_p->nr_sects <= bsd_p->p_offset - || lin_p->start_sect >= bsd_p->p_offset + bsd_p->p_size) - continue; - /* equal -> no need to add */ - if (lin_p->start_sect == bsd_p->p_offset && - lin_p->nr_sects == bsd_p->p_size) - return; - /* bsd living within dos partition */ - if (lin_p->start_sect <= bsd_p->p_offset && lin_p->start_sect - + lin_p->nr_sects >= bsd_p->p_offset + bsd_p->p_size) { -#ifdef DEBUG_BSD_DISKLABEL - printk("w: %d %ld+%ld,%d+%d", - lin_p - hd->part, - lin_p->start_sect, lin_p->nr_sects, - bsd_p->p_offset, bsd_p->p_size); -#endif - break; - } - /* ouch: bsd and linux overlap. Don't even try for that partition */ -#ifdef DEBUG_BSD_DISKLABEL - printk("???: %d %ld+%ld,%d+%d", - lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects, - bsd_p->p_offset, bsd_p->p_size); -#endif - printk("???"); - return; - } /* if the bsd partition is not currently known to linux, we end - * up here - */ - add_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size); - current_minor++; -} -/* - * Create devices for BSD partitions listed in a disklabel, under a - * dos-like partition. See extended_partition() for more information. - */ -static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev, - int max_partitions) -{ - struct buffer_head *bh; - struct bsd_disklabel *l; - struct bsd_partition *p; - int mask = (1 << hd->minor_shift) - 1; - - if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) - return; - l = (struct bsd_disklabel *) (bh->b_data+512); - if (l->d_magic != BSD_DISKMAGIC) { - brelse(bh); - return; - } - - if (l->d_npartitions < max_partitions) - max_partitions = l->d_npartitions; - for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { - if ((current_minor & mask) >= (4 + hd->max_p)) - break; - - if (p->p_fstype != BSD_FS_UNUSED) - check_and_add_bsd_partition(hd, p, dev); - } - - /* Use bforget(), as we have changed the disk setup */ - bforget(bh); - -} -#endif - -#ifdef CONFIG_UNIXWARE_DISKLABEL -/* - * Create devices for Unixware partitions listed in a disklabel, under a - * dos-like partition. See extended_partition() for more information. - */ -static void unixware_partition(struct gendisk *hd, kdev_t dev) -{ - struct buffer_head *bh; - struct unixware_disklabel *l; - struct unixware_slice *p; - int mask = (1 << hd->minor_shift) - 1; - - if (!(bh = bread(dev, 14, get_ptable_blocksize(dev)))) - return; - l = (struct unixware_disklabel *) (bh->b_data+512); - if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC || - le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) { - brelse(bh); - return; - } - printk(" <unixware:"); - p = &l->vtoc.v_slice[1]; - /* I omit the 0th slice as it is the same as whole disk. */ - while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { - if ((current_minor & mask) == 0) - break; - - if (p->s_label != UNIXWARE_FS_UNUSED) { - add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); - current_minor++; - } - p++; - } - /* Use bforget, as we have changed the disk setup */ - bforget(bh); - printk(" >"); -} -#endif - -static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) -{ - int i, minor = current_minor; - struct buffer_head *bh; - struct partition *p; - unsigned char *data; - int mask = (1 << hd->minor_shift) - 1; - int sector_size = get_hardsect_size(dev) / 512; -#ifdef CONFIG_BSD_DISKLABEL - /* no bsd disklabel as a default */ - kdev_t bsd_kdev = 0; - int bsd_maxpart = BSD_MAXPARTITIONS; -#endif -#ifdef CONFIG_BLK_DEV_IDE - int tested_for_xlate = 0; - -read_mbr: -#endif - if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) { - printk(" unable to read partition table\n"); - return -1; - } - data = bh->b_data; -#ifdef CONFIG_BLK_DEV_IDE -check_table: -#endif - /* Use bforget(), because we have potentially changed the disk geometry */ - if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { - bforget(bh); - return 0; - } - p = (struct partition *) (0x1be + data); - -#ifdef CONFIG_BLK_DEV_IDE - if (!tested_for_xlate++) { /* Do this only once per disk */ - /* - * Look for various forms of IDE disk geometry translation - */ - extern int ide_xlate_1024(kdev_t, int, const char *); - unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2)); - if (SYS_IND(p) == EZD_PARTITION) { - /* - * The remainder of the disk must be accessed using - * a translated geometry that reduces the number of - * apparent cylinders to less than 1024 if possible. - * - * ide_xlate_1024() will take care of the necessary - * adjustments to fool fdisk/LILO and partition check. - */ - if (ide_xlate_1024(dev, -1, " [EZD]")) { - data += 512; - goto check_table; - } - } else if (SYS_IND(p) == DM6_PARTITION) { - - /* - * Everything on the disk is offset by 63 sectors, - * including a "new" MBR with its own partition table, - * and the remainder of the disk must be accessed using - * a translated geometry that reduces the number of - * apparent cylinders to less than 1024 if possible. - * - * ide_xlate_1024() will take care of the necessary - * adjustments to fool fdisk/LILO and partition check. - */ - if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) { - bforget(bh); - goto read_mbr; /* start over with new MBR */ - } - } else if (sig <= 0x1ae && - *(unsigned short *)(data + sig) == cpu_to_le16(0x55AA) && - (1 & *(unsigned char *)(data + sig + 2))) { - /* DM6 signature in MBR, courtesy of OnTrack */ - (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]"); - } else if (SYS_IND(p) == DM6_AUX1PARTITION || SYS_IND(p) == DM6_AUX3PARTITION) { - /* - * DM6 on other than the first (boot) drive - */ - (void) ide_xlate_1024(dev, 0, " [DM6:AUX]"); - } else { - /* - * Examine the partition table for common translations. - * This is useful for drives in situations where the - * translated geometry is unavailable from the BIOS. - */ - for (i = 0; i < 4; i++) { - struct partition *q = &p[i]; - if (NR_SECTS(q) - && (q->sector & 63) == 1 - && (q->end_sector & 63) == 63) { - unsigned int heads = q->end_head + 1; - if (heads == 32 || heads == 64 || - heads == 128 || heads == 240 || - heads == 255) { - (void) ide_xlate_1024(dev, heads, " [PTBL]"); - break; - } - } - } - } - } -#endif /* CONFIG_BLK_DEV_IDE */ - - current_minor += 4; /* first "extra" minor (for extended partitions) */ - for (i=1 ; i<=4 ; minor++,i++,p++) { - if (!NR_SECTS(p)) - continue; - add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size); - if (is_extended_partition(p)) { - printk(" <"); - /* - * If we are rereading the partition table, we need - * to set the size of the partition so that we will - * be able to bread the block containing the extended - * partition info. - */ - hd->sizes[minor] = hd->part[minor].nr_sects - >> (BLOCK_SIZE_BITS - 9); - extended_partition(hd, MKDEV(hd->major, minor)); - printk(" >"); - /* prevent someone doing mkfs or mkswap on an - extended partition, but leave room for LILO */ - if (hd->part[minor].nr_sects > 2) - hd->part[minor].nr_sects = 2; - } -#ifdef CONFIG_BSD_DISKLABEL - /* tag first disklabel for late recognition */ - if (SYS_IND(p) == BSD_PARTITION || SYS_IND(p) == NETBSD_PARTITION) { - printk("!"); - if (!bsd_kdev) - bsd_kdev = MKDEV(hd->major, minor); - } else if (SYS_IND(p) == OPENBSD_PARTITION) { - printk("!"); - if (!bsd_kdev) { - bsd_kdev = MKDEV(hd->major, minor); - bsd_maxpart = OPENBSD_MAXPARTITIONS; - } - } -#endif -#ifdef CONFIG_UNIXWARE_DISKLABEL - if (SYS_IND(p) == UNIXWARE_PARTITION) - unixware_partition(hd, MKDEV(hd->major, minor)); -#endif -#ifdef CONFIG_SOLARIS_X86_PARTITION - - /* james@bpgc.com: Solaris has a nasty indicator: 0x82 - * which also means linux swap. For that reason, all - * of the prints are done inside the - * solaris_x86_partition routine */ - - if(SYS_IND(p) == SOLARIS_X86_PARTITION) { - solaris_x86_partition(hd, MKDEV(hd->major, minor), - first_sector+START_SECT(p)); - } -#endif - } -#ifdef CONFIG_BSD_DISKLABEL - if (bsd_kdev) { - printk(" <"); - bsd_disklabel_partition(hd, bsd_kdev, bsd_maxpart); - printk(" >"); - } -#endif - /* - * Check for old-style Disk Manager partition table - */ - if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) { - p = (struct partition *) (0x1be + data); - for (i = 4 ; i < 16 ; i++, current_minor++) { - p--; - if ((current_minor & mask) == 0) - break; - if (!(START_SECT(p) && NR_SECTS(p))) - continue; - add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); - } - } - printk("\n"); - bforget(bh); - return 1; -} - -#endif /* CONFIG_MSDOS_PARTITION */ - -#ifdef CONFIG_OSF_PARTITION - -static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) -{ - int i; - int mask = (1 << hd->minor_shift) - 1; - struct buffer_head *bh; - struct disklabel { - u32 d_magic; - u16 d_type,d_subtype; - u8 d_typename[16]; - u8 d_packname[16]; - u32 d_secsize; - u32 d_nsectors; - u32 d_ntracks; - u32 d_ncylinders; - u32 d_secpercyl; - u32 d_secprtunit; - u16 d_sparespertrack; - u16 d_sparespercyl; - u32 d_acylinders; - u16 d_rpm, d_interleave, d_trackskew, d_cylskew; - u32 d_headswitch, d_trkseek, d_flags; - u32 d_drivedata[5]; - u32 d_spare[5]; - u32 d_magic2; - u16 d_checksum; - u16 d_npartitions; - u32 d_bbsize, d_sbsize; - struct d_partition { - u32 p_size; - u32 p_offset; - u32 p_fsize; - u8 p_fstype; - u8 p_frag; - u16 p_cpg; - } d_partitions[8]; - } * label; - struct d_partition * partition; -#define DISKLABELMAGIC (0x82564557UL) - - if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) { - printk("unable to read partition table\n"); - return -1; - } - label = (struct disklabel *) (bh->b_data+64); - partition = label->d_partitions; - if (label->d_magic != DISKLABELMAGIC) { - brelse(bh); - return 0; - } - if (label->d_magic2 != DISKLABELMAGIC) { - brelse(bh); - return 0; - } - for (i = 0 ; i < label->d_npartitions; i++, partition++) { - if ((current_minor & mask) == 0) - break; - if (partition->p_size) - add_partition(hd, current_minor, - first_sector+partition->p_offset, - partition->p_size); - current_minor++; - } - printk("\n"); - brelse(bh); - return 1; -} - -#endif /* CONFIG_OSF_PARTITION */ - -#ifdef CONFIG_SUN_PARTITION - -static int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) -{ - int i, csum; - unsigned short *ush; - struct buffer_head *bh; - struct sun_disklabel { - unsigned char info[128]; /* Informative text string */ - unsigned char spare[292]; /* Boot information etc. */ - unsigned short rspeed; /* Disk rotational speed */ - unsigned short pcylcount; /* Physical cylinder count */ - unsigned short sparecyl; /* extra sects per cylinder */ - unsigned char spare2[4]; /* More magic... */ - unsigned short ilfact; /* Interleave factor */ - unsigned short ncyl; /* Data cylinder count */ - unsigned short nacyl; /* Alt. cylinder count */ - unsigned short ntrks; /* Tracks per cylinder */ - unsigned short nsect; /* Sectors per track */ - unsigned char spare3[4]; /* Even more magic... */ - struct sun_partition { - __u32 start_cylinder; - __u32 num_sectors; - } partitions[8]; - unsigned short magic; /* Magic number */ - unsigned short csum; /* Label xor'd checksum */ - } * label; - struct sun_partition *p; - unsigned long spc; -#define SUN_LABEL_MAGIC 0xDABE - - if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) { - printk("Dev %s: unable to read partition table\n", - kdevname(dev)); - return -1; - } - label = (struct sun_disklabel *) bh->b_data; - p = label->partitions; - if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) { - printk("Dev %s Sun disklabel: bad magic %04x\n", - kdevname(dev), be16_to_cpu(label->magic)); - brelse(bh); - return 0; - } - /* Look at the checksum */ - ush = ((unsigned short *) (label+1)) - 1; - for(csum = 0; ush >= ((unsigned short *) label);) - csum ^= *ush--; - if(csum) { - printk("Dev %s Sun disklabel: Csum bad, label corrupted\n", - kdevname(dev)); - brelse(bh); - return 0; - } - /* All Sun disks have 8 partition entries */ - spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect); - for(i=0; i < 8; i++, p++) { - unsigned long st_sector; - int num_sectors; - - st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc; - num_sectors = be32_to_cpu(p->num_sectors); - if (num_sectors) - add_partition(hd, current_minor, st_sector, num_sectors); - current_minor++; - } - printk("\n"); - brelse(bh); - return 1; -} - -#endif /* CONFIG_SUN_PARTITION */ - -#ifdef CONFIG_SGI_PARTITION - -static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) -{ - int i, csum, magic; - unsigned int *ui, start, blocks, cs; - struct buffer_head *bh; - struct sgi_disklabel { - int magic_mushroom; /* Big fat spliff... */ - short root_part_num; /* Root partition number */ - short swap_part_num; /* Swap partition number */ - char boot_file[16]; /* Name of boot file for ARCS */ - unsigned char _unused0[48]; /* Device parameter useless crapola.. */ - struct sgi_volume { - char name[8]; /* Name of volume */ - int block_num; /* Logical block number */ - int num_bytes; /* How big, in bytes */ - } volume[15]; - struct sgi_partition { - int num_blocks; /* Size in logical blocks */ - int first_block; /* First logical block */ - int type; /* Type of this partition */ - } partitions[16]; - int csum; /* Disk label checksum */ - int _unused1; /* Padding */ - } *label; - struct sgi_partition *p; -#define SGI_LABEL_MAGIC 0x0be5a941 - - if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) { - printk("Dev %s: unable to read partition table\n", kdevname(dev)); - return -1; - } - label = (struct sgi_disklabel *) bh->b_data; - p = &label->partitions[0]; - magic = label->magic_mushroom; - if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) { - printk("Dev %s SGI disklabel: bad magic %08x\n", - kdevname(dev), magic); - brelse(bh); - return 0; - } - ui = ((unsigned int *) (label + 1)) - 1; - for(csum = 0; ui >= ((unsigned int *) label);) { - cs = *ui--; - csum += be32_to_cpu(cs); - } - if(csum) { - printk("Dev %s SGI disklabel: csum bad, label corrupted\n", - kdevname(dev)); - brelse(bh); - return 0; - } - /* All SGI disk labels have 16 partitions, disks under Linux only - * have 15 minor's. Luckily there are always a few zero length - * partitions which we don't care about so we never overflow the - * current_minor. - */ - for(i = 0; i < 16; i++, p++) { - blocks = be32_to_cpu(p->num_blocks); - start = be32_to_cpu(p->first_block); - if(!blocks) - continue; - add_partition(hd, current_minor, start, blocks); - current_minor++; - } - printk("\n"); - brelse(bh); - return 1; -} - -#endif - -#ifdef CONFIG_AMIGA_PARTITION -#include <linux/affs_hardblocks.h> - -static __inline__ u32 -checksum_block(u32 *m, int size) -{ - u32 sum = 0; - - while (size--) - sum += htonl(*m++); - return sum; -} +extern void console_map_init(void); +extern int soc_probe(void); +extern int atmdev_init(void); -static int -amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) +void __init device_init(void) { - struct buffer_head *bh; - struct RigidDiskBlock *rdb; - struct PartitionBlock *pb; - int start_sect; - int nr_sects; - int blk; - int part, res; - int old_blocksize; - int blocksize; - - old_blocksize = get_ptable_blocksize(dev); - blocksize = get_hardsect_size(dev); - - set_blocksize(dev,blocksize); - res = 0; - - for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) { - if(!(bh = bread(dev,blk,blocksize))) { - printk("Dev %s: unable to read RDB block %d\n", - kdevname(dev),blk); - goto rdb_done; - } - if (*(u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) { - rdb = (struct RigidDiskBlock *)bh->b_data; - if (checksum_block((u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) { - /* Try again with 0xdc..0xdf zeroed, Windows might have - * trashed it. - */ - *(u32 *)(&bh->b_data[0xdc]) = 0; - if (checksum_block((u32 *)bh->b_data, - htonl(rdb->rdb_SummedLongs) & 0x7F)) { - brelse(bh); - printk("Dev %s: RDB in block %d has bad checksum\n", - kdevname(dev),blk); - continue; - } - printk("Warning: Trashed word at 0xd0 in block %d " - "ignored in checksum calculation\n",blk); - } - printk(" RDSK"); - blk = htonl(rdb->rdb_PartitionList); - brelse(bh); - for (part = 1; blk > 0 && part <= 16; part++) { - if (!(bh = bread(dev,blk,blocksize))) { - printk("Dev %s: unable to read partition block %d\n", - kdevname(dev),blk); - goto rdb_done; - } - pb = (struct PartitionBlock *)bh->b_data; - blk = htonl(pb->pb_Next); - if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block( - (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) { - - /* Tell Kernel about it */ - - if (!(nr_sects = (htonl(pb->pb_Environment[10]) + 1 - - htonl(pb->pb_Environment[9])) * - htonl(pb->pb_Environment[3]) * - htonl(pb->pb_Environment[5]))) { - brelse(bh); - continue; - } - start_sect = htonl(pb->pb_Environment[9]) * - htonl(pb->pb_Environment[3]) * - htonl(pb->pb_Environment[5]); - add_partition(hd,current_minor,start_sect,nr_sects); - current_minor++; - res = 1; - } - brelse(bh); - } - printk("\n"); - } - else - brelse(bh); - } - -rdb_done: - set_blocksize(dev,old_blocksize); - return res; -} -#endif /* CONFIG_AMIGA_PARTITION */ - -#ifdef CONFIG_MAC_PARTITION -#include <linux/ctype.h> - -/* - * Code to understand MacOS partition tables. - */ - -#define MAC_PARTITION_MAGIC 0x504d - -/* type field value for A/UX or other Unix partitions */ -#define APPLE_AUX_TYPE "Apple_UNIX_SVR2" - -struct mac_partition { - __u16 signature; /* expected to be MAC_PARTITION_MAGIC */ - __u16 res1; - __u32 map_count; /* # blocks in partition map */ - __u32 start_block; /* absolute starting block # of partition */ - __u32 block_count; /* number of blocks in partition */ - char name[32]; /* partition name */ - char type[32]; /* string type description */ - __u32 data_start; /* rel block # of first data block */ - __u32 data_count; /* number of data blocks */ - __u32 status; /* partition status bits */ - __u32 boot_start; - __u32 boot_size; - __u32 boot_load; - __u32 boot_load2; - __u32 boot_entry; - __u32 boot_entry2; - __u32 boot_cksum; - char processor[16]; /* identifies ISA of boot */ - /* there is more stuff after this that we don't need */ -}; - -#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */ - -#define MAC_DRIVER_MAGIC 0x4552 - -/* Driver descriptor structure, in block 0 */ -struct mac_driver_desc { - __u16 signature; /* expected to be MAC_DRIVER_MAGIC */ - __u16 block_size; - __u32 block_count; - /* ... more stuff */ -}; - -static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec) -{ - struct buffer_head *bh; - int blk, blocks_in_map; - int dev_bsize, dev_pos, pos; - unsigned secsize; -#ifdef CONFIG_PPC - int first_bootable = 1; -#endif - struct mac_partition *part; - struct mac_driver_desc *md; - - dev_bsize = get_ptable_blocksize(dev); - dev_pos = 0; - /* Get 0th block and look at the first partition map entry. */ - if ((bh = bread(dev, 0, dev_bsize)) == 0) { - printk("%s: error reading partition table\n", - kdevname(dev)); - return -1; - } - md = (struct mac_driver_desc *) bh->b_data; - if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) { - brelse(bh); - return 0; - } - secsize = be16_to_cpu(md->block_size); - if (secsize >= dev_bsize) { - brelse(bh); - dev_pos = secsize; - if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) { - printk("%s: error reading partition table\n", - kdevname(dev)); - return -1; - } - } - part = (struct mac_partition *) (bh->b_data + secsize - dev_pos); - if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) { - brelse(bh); - return 0; /* not a MacOS disk */ - } - blocks_in_map = be32_to_cpu(part->map_count); - for (blk = 1; blk <= blocks_in_map; ++blk) { - pos = blk * secsize; - if (pos >= dev_pos + dev_bsize) { - brelse(bh); - dev_pos = pos; - if ((bh = bread(dev, pos/dev_bsize, dev_bsize)) == 0) { - printk("%s: error reading partition table\n", - kdevname(dev)); - return -1; - } - } - part = (struct mac_partition *) (bh->b_data + pos - dev_pos); - if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) - break; - blocks_in_map = be32_to_cpu(part->map_count); - add_partition(hd, current_minor, - fsec + be32_to_cpu(part->start_block) * (secsize/512), - be32_to_cpu(part->block_count) * (secsize/512)); - -#ifdef CONFIG_PPC - /* - * If this is the first bootable partition, tell the - * setup code, in case it wants to make this the root. - */ - if ( (_machine == _MACH_Pmac) && first_bootable - && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE) - && strcasecmp(part->processor, "powerpc") == 0) { - note_bootable_part(dev, blk); - first_bootable = 0; - } -#endif /* CONFIG_PPC */ - - ++current_minor; - } - brelse(bh); - printk("\n"); - return 1; -} - -#endif /* CONFIG_MAC_PARTITION */ - -#ifdef CONFIG_ATARI_PARTITION -#include <linux/atari_rootsec.h> - -/* ++guenther: this should be settable by the user ("make config")?. - */ -#define ICD_PARTS - -static int atari_partition (struct gendisk *hd, kdev_t dev, - unsigned long first_sector) -{ - int minor = current_minor, m_lim = current_minor + hd->max_p; - struct buffer_head *bh; - struct rootsector *rs; - struct partition_info *pi; - ulong extensect; - unsigned int psum; - int i; -#ifdef ICD_PARTS - int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ -#endif - - bh = bread (dev, 0, get_ptable_blocksize(dev)); - if (!bh) { - printk (" unable to read block 0 (partition table)\n"); - return -1; - } - - /* Verify this is an Atari rootsector: */ - psum=0; - for (i=0;i<256;i++) { - psum+=ntohs(((__u16 *) (bh->b_data))[i]); - } - if ((psum & 0xFFFF) != 0x1234) { - brelse(bh); - return 0; - } - - rs = (struct rootsector *) bh->b_data; - pi = &rs->part[0]; - printk (" AHDI"); - for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++) - { - if (pi->flg & 1) - /* active partition */ - { - if (memcmp (pi->id, "XGM", 3) == 0) - /* extension partition */ - { - struct rootsector *xrs; - struct buffer_head *xbh; - ulong partsect; - -#ifdef ICD_PARTS - part_fmt = 1; -#endif - printk(" XGM<"); - partsect = extensect = ntohl(pi->st); - while (1) - { - xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev)); - if (!xbh) - { - printk (" block %ld read failed\n", partsect); - brelse(bh); - return 0; - } - if (partsect & 1) - xrs = (struct rootsector *) &xbh->b_data[512]; - else - xrs = (struct rootsector *) &xbh->b_data[0]; - - /* ++roman: sanity check: bit 0 of flg field must be set */ - if (!(xrs->part[0].flg & 1)) { - printk( "\nFirst sub-partition in extended partition is not valid!\n" ); - break; - } - - add_partition(hd, minor, partsect + ntohl(xrs->part[0].st), - ntohl(xrs->part[0].siz)); - - if (!(xrs->part[1].flg & 1)) { - /* end of linked partition list */ - brelse( xbh ); - break; - } - if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { - printk( "\nID of extended partition is not XGM!\n" ); - brelse( xbh ); - break; - } - - partsect = ntohl(xrs->part[1].st) + extensect; - brelse (xbh); - minor++; - if (minor >= m_lim) { - printk( "\nMaximum number of partitions reached!\n" ); - break; - } - } - printk(" >"); - } - else - { - /* we don't care about other id's */ - add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz)); - } - } - } -#ifdef ICD_PARTS - if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */ - { - pi = &rs->icdpart[0]; - /* sanity check: no ICD format if first partition invalid */ - if (memcmp (pi->id, "GEM", 3) == 0 || - memcmp (pi->id, "BGM", 3) == 0 || - memcmp (pi->id, "LNX", 3) == 0 || - memcmp (pi->id, "SWP", 3) == 0 || - memcmp (pi->id, "RAW", 3) == 0 ) - { - printk(" ICD<"); - for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++) - { - /* accept only GEM,BGM,RAW,LNX,SWP partitions */ - if (pi->flg & 1 && - (memcmp (pi->id, "GEM", 3) == 0 || - memcmp (pi->id, "BGM", 3) == 0 || - memcmp (pi->id, "LNX", 3) == 0 || - memcmp (pi->id, "SWP", 3) == 0 || - memcmp (pi->id, "RAW", 3) == 0) ) - { - part_fmt = 2; - add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz)); - } - } - printk(" >"); - } - } -#endif - brelse (bh); - - printk ("\n"); - - return 1; -} -#endif /* CONFIG_ATARI_PARTITION */ - -#ifdef CONFIG_ULTRIX_PARTITION - -static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) -{ - int i, minor = current_minor; - struct buffer_head *bh; - struct ultrix_disklabel { - long pt_magic; /* magic no. indicating part. info exits */ - int pt_valid; /* set by driver if pt is current */ - struct pt_info { - int pi_nblocks; /* no. of sectors */ - unsigned long pi_blkoff; /* block offset for start */ - } pt_part[8]; - } *label; - -#define PT_MAGIC 0x032957 /* Partition magic number */ -#define PT_VALID 1 /* Indicates if struct is valid */ - -#define SBLOCK ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \ - /get_ptable_blocksize(dev))) - - bh = bread (dev, SBLOCK, get_ptable_blocksize(dev)); - if (!bh) { - printk (" unable to read block 0x%lx\n", SBLOCK); - return -1; - } - - label = (struct ultrix_disklabel *)(bh->b_data - + get_ptable_blocksize(dev) - - sizeof(struct ultrix_disklabel)); - - if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) { - for (i=0; i<8; i++, minor++) - if (label->pt_part[i].pi_nblocks) - add_partition(hd, minor, - label->pt_part[i].pi_blkoff, - label->pt_part[i].pi_nblocks); - brelse(bh); - printk ("\n"); - return 1; - } else { - brelse(bh); - return 0; - } -} - -#endif /* CONFIG_ULTRIX_PARTITION */ - -#ifdef CONFIG_ULTRIX_PARTITION - -static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) -{ - int i, minor = current_minor; - struct buffer_head *bh; - struct ultrix_disklabel { - s32 pt_magic; /* magic no. indicating part. info exits */ - s32 pt_valid; /* set by driver if pt is current */ - struct pt_info { - s32 pi_nblocks; /* no. of sectors */ - u32 pi_blkoff; /* block offset for start */ - } pt_part[8]; - } *label; - -#define PT_MAGIC 0x032957 /* Partition magic number */ -#define PT_VALID 1 /* Indicates if struct is valid */ - -#define SBLOCK ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \ - /get_ptable_blocksize(dev))) - - bh = bread (dev, SBLOCK, get_ptable_blocksize(dev)); - if (!bh) { - printk (" unable to read block 0x%lx\n", SBLOCK); - return -1; - } - - label = (struct ultrix_disklabel *)(bh->b_data - + get_ptable_blocksize(dev) - - sizeof(struct ultrix_disklabel)); - - if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) { - for (i=0; i<8; i++, minor++) - if (label->pt_part[i].pi_nblocks) - add_partition(hd, minor, - label->pt_part[i].pi_blkoff, - label->pt_part[i].pi_nblocks); - brelse(bh); - printk ("\n"); - return 1; - } else { - brelse(bh); - return 0; - } -} - -#endif /* CONFIG_ULTRIX_PARTITION */ - -static void check_partition(struct gendisk *hd, kdev_t dev) -{ - static int first_time = 1; - unsigned long first_sector; - char buf[40]; - - if (first_time) - printk(KERN_INFO "Partition check:\n"); - first_time = 0; - first_sector = hd->part[MINOR(dev)].start_sect; - - /* - * This is a kludge to allow the partition check to be - * skipped for specific drives (e.g. IDE CD-ROM drives) - */ - if ((int)first_sector == -1) { - hd->part[MINOR(dev)].start_sect = 0; - return; - } - - printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); -#ifdef CONFIG_MSDOS_PARTITION - if (msdos_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_OSF_PARTITION - if (osf_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_SUN_PARTITION - if(sun_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_AMIGA_PARTITION - if(amiga_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_ATARI_PARTITION - if(atari_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_MAC_PARTITION - if (mac_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_SGI_PARTITION - if(sgi_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_ULTRIX_PARTITION - if(ultrix_partition(hd, dev, first_sector)) - return; -#endif -#ifdef CONFIG_ULTRIX_PARTITION - if(ultrix_partition(hd, dev, first_sector)) - return; -#endif - printk(" unknown partition table\n"); -} - -/* This function is used to re-read partition tables for removable disks. - Much of the cleanup from the old partition tables should have already been - done */ - -/* This function will re-read the partition tables for a given device, -and set things back up again. There are some important caveats, -however. You must ensure that no one is using the device, and no one -can start using the device while this function is being executed. */ - -void resetup_one_dev(struct gendisk *dev, int drive) -{ - int i; - int first_minor = drive << dev->minor_shift; - int end_minor = first_minor + dev->max_p; - - blk_size[dev->major] = NULL; - current_minor = 1 + first_minor; - check_partition(dev, MKDEV(dev->major, first_minor)); - - /* - * We need to set the sizes array before we will be able to access - * any of the partitions on this device. - */ - if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ - for (i = first_minor; i < end_minor; i++) - dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); - blk_size[dev->major] = dev->sizes; - } -} - -static inline void setup_dev(struct gendisk *dev) -{ - int i, drive; - int end_minor = dev->max_nr * dev->max_p; - - blk_size[dev->major] = NULL; - for (i = 0; i < end_minor; i++) { - dev->part[i].start_sect = 0; - dev->part[i].nr_sects = 0; - dev->sizes[i] = 0; - } - dev->init(dev); - for (drive = 0; drive < dev->nr_real; drive++) - resetup_one_dev(dev, drive); -} - -void __init device_setup(void) -{ - extern void console_map_init(void); - extern void cpqarray_init(void); -#ifdef CONFIG_PARPORT - extern int parport_init(void) __init; -#endif -#ifdef CONFIG_MD_BOOT - extern void md_setup_drive(void) __init; -#endif -#ifdef CONFIG_FC4_SOC - extern int soc_probe(void); -#endif - struct gendisk *p; - #ifdef CONFIG_PARPORT parport_init(); #endif @@ -1463,6 +42,9 @@ void __init device_setup(void) chr_dev_init(); blk_dev_init(); sti(); +#ifdef CONFIG_BLK_DEV_DAC960 + DAC960_Initialize(); +#endif #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ soc_probe(); @@ -1473,46 +55,13 @@ void __init device_setup(void) #ifdef CONFIG_BLK_CPQ_DA cpqarray_init(); #endif -#ifdef CONFIG_INET +#ifdef CONFIG_NET net_dev_init(); #endif +#ifdef CONFIG_ATM + (void) atmdev_init(); +#endif #ifdef CONFIG_VT console_map_init(); #endif - - for (p = gendisk_head ; p ; p=p->next) - setup_dev(p); - -#ifdef CONFIG_BLK_DEV_RAM -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start && mount_initrd) initrd_load(); - else -#endif - rd_load(); -#endif -#ifdef CONFIG_MD_BOOT - md_setup_drive(); -#endif } - -#ifdef CONFIG_PROC_FS -int get_partition_list(char * page) -{ - struct gendisk *p; - char buf[40]; - int n, len; - - len = sprintf(page, "major minor #blocks name\n\n"); - for (p = gendisk_head; p; p = p->next) { - for (n=0; n < (p->nr_real << p->minor_shift); n++) { - if (p->part[n].nr_sects && len < PAGE_SIZE - 80) { - len += sprintf(page+len, - "%4d %4d %10d %s\n", - p->major, n, p->sizes[n], - disk_name(p, n, buf)); - } - } - } - return len; -} -#endif diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 164835bfc..49527026a 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -21,12 +21,12 @@ * Removed 99% of above. Use Mark's ide driver for those options. * This is now a lightweight ST-506 driver. (Paul Gortmaker) * + * Modified 1995 Russell King for ARM processor. */ /* Uncomment the following if you want verbose error reports. */ /* #define VERBOSE_ERRORS */ -#include <asm/irq.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> @@ -40,6 +40,7 @@ #include <linux/ioport.h> #include <linux/mc146818rtc.h> /* CMOS defines */ #include <linux/init.h> +#include <linux/blkpg.h> #define REALLY_SLOW_IO #include <asm/system.h> @@ -49,6 +50,14 @@ #define MAJOR_NR HD_MAJOR #include <linux/blk.h> +#ifdef __arm__ +#undef HD_IRQ +#endif +#include <asm/irq.h> +#ifdef __arm__ +#define HD_IRQ IRQ_HARDDISK +#endif + static int revalidate_hddisk(kdev_t, int); #define HD_DELAY 0 @@ -64,14 +73,14 @@ static int revalidate_hddisk(kdev_t, int); static void recal_intr(void); static void bad_rw_intr(void); -static char recalibrate[MAX_HD] = { 0, }; -static char special_op[MAX_HD] = { 0, }; -static int access_count[MAX_HD] = {0, }; -static char busy[MAX_HD] = {0, }; +static char recalibrate[MAX_HD]; +static char special_op[MAX_HD]; +static int access_count[MAX_HD]; +static char busy[MAX_HD]; static DECLARE_WAIT_QUEUE_HEAD(busy_wait); -static int reset = 0; -static int hd_error = 0; +static int reset; +static int hd_error; #define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0) @@ -86,13 +95,14 @@ struct hd_i_struct { static struct hd_i_struct hd_info[] = { HD_TYPE }; static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct))); #else -static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; -static int NR_HD = 0; +static struct hd_i_struct hd_info[MAX_HD]; +static int NR_HD; #endif -static struct hd_struct hd[MAX_HD<<6]={{0,0},}; -static int hd_sizes[MAX_HD<<6] = {0, }; -static int hd_blocksizes[MAX_HD<<6] = {0, }; +static struct hd_struct hd[MAX_HD<<6]; +static int hd_sizes[MAX_HD<<6]; +static int hd_blocksizes[MAX_HD<<6]; +static int hd_hardsectsizes[MAX_HD<<6]; #if (HD_DELAY > 0) unsigned long last_req; @@ -611,7 +621,7 @@ static int hd_ioctl(struct inode * inode, struct file * file, (long *) arg); case BLKRRPART: /* Re-read partition tables */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_hddisk(inode->i_rdev, 1); @@ -746,6 +756,17 @@ static void hd_geninit(struct gendisk *ignored) } } #endif /* __i386__ */ +#ifdef __arm__ + if (!NR_HD) { + /* We don't know anything about the drive. This means + * that you *MUST* specify the drive parameters to the + * kernel yourself. + */ + printk("hd: no drives specified - use hd=cyl,head,sectors" + " on kernel command line\n"); + } +#endif + for (drive=0 ; drive < NR_HD ; drive++) { hd[drive<<6].nr_sects = hd_info[drive].head * hd_info[drive].sect * hd_info[drive].cyl; @@ -764,9 +785,12 @@ static void hd_geninit(struct gendisk *ignored) } hd_gendisk.nr_real = NR_HD; - for(drive=0; drive < (MAX_HD << 6); drive++) + for(drive=0; drive < (MAX_HD << 6); drive++) { hd_blocksizes[drive] = 1024; + hd_hardsectsizes[drive] = 512; + } blksize_size[MAJOR_NR] = hd_blocksizes; + hardsect_size[MAJOR_NR] = hd_hardsectsizes; } static struct file_operations hd_fops = { diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c index 79df61b1f..284bf40bc 100644 --- a/drivers/block/hpt34x.c +++ b/drivers/block/hpt34x.c @@ -1,8 +1,7 @@ /* - * linux/drivers/block/hpt34x.c Version 0.24 July 3, 1999 + * linux/drivers/block/hpt34x.c Version 0.25 July 11, 1999 * * Copyright (C) 1998-99 Andre Hedrick - * (hedrick@astro.dyer.vanderbilt.edu) * * 00:12.0 Unknown mass storage controller: * Triones Technologies, Inc. @@ -118,9 +117,14 @@ static int config_chipset_for_dma (ide_drive_t *drive) return ((int) ide_dma_off_quietly); #endif /* HPT343_DISABLE_ALL_DMAING */ - if (id->dma_ultra & 0x0004) { + if (id->dma_ultra & 0x0010) { + goto backspeed; + } else if (id->dma_ultra & 0x0008) { + goto backspeed; + } else if (id->dma_ultra & 0x0004) { +backspeed: if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0404; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -128,7 +132,7 @@ static int config_chipset_for_dma (ide_drive_t *drive) speed = XFER_UDMA_2; } else if (id->dma_ultra & 0x0002) { if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0202; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -136,7 +140,7 @@ static int config_chipset_for_dma (ide_drive_t *drive) speed = XFER_UDMA_1; } else if (id->dma_ultra & 0x0001) { if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0101; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -190,7 +194,8 @@ static int config_chipset_for_dma (ide_drive_t *drive) (void) hpt34x_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); @@ -335,62 +340,44 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) */ #define HPT34X_PCI_INIT_REG 0x80 -__initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) { - int i; unsigned short cmd; - unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; -#if 0 - unsigned char misc10 = inb(hpt34xIoBase + 0x0010); - unsigned char misc11 = inb(hpt34xIoBase + 0x0011); -#endif pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); pci_read_config_word(dev, PCI_COMMAND, &cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); - - dev->base_address[0] = (hpt34xIoBase + 0x20); - dev->base_address[1] = (hpt34xIoBase + 0x34); - dev->base_address[2] = (hpt34xIoBase + 0x28); - dev->base_address[3] = (hpt34xIoBase + 0x3c); - - for(i=0; i<4; i++) - dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; - - /* - * Since 20-23 can be assigned and are R/W, we correct them. - */ - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]); - pci_write_config_word(dev, PCI_COMMAND, cmd); - -#if 0 - outb(misc10|0x78, (hpt34xIoBase + 0x0010)); - outb(misc11, (hpt34xIoBase + 0x0011)); -#endif - -#ifdef DEBUG - printk("%s: 0x%02x 0x%02x\n", - (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name, - inb(hpt34xIoBase + 0x0010), - inb(hpt34xIoBase + 0x0011)); -#endif - if (cmd & PCI_COMMAND_MEMORY) { - if (dev->rom_address) { - pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address); + if (dev->resource[PCI_ROM_RESOURCE].start) { + pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start); } pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } else { + int i = 0; + unsigned long hpt34xIoBase = dev->resource[4].start; + + pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); + dev->resource[0].start = (hpt34xIoBase + 0x20); + dev->resource[1].start = (hpt34xIoBase + 0x34); + dev->resource[2].start = (hpt34xIoBase + 0x28); + dev->resource[3].start = (hpt34xIoBase + 0x3c); + for(i=0; i<4; i++) + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; + /* + * Since 20-23 can be assigned and are R/W, we correct them. + */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); + + pci_write_config_word(dev, PCI_COMMAND, cmd); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } return dev->irq; } -__initfunc(void ide_init_hpt34x (ide_hwif_t *hwif)) +void __init ide_init_hpt34x (ide_hwif_t *hwif) { hwif->tuneproc = &hpt34x_tune_drive; if (hwif->dma_base) { @@ -398,7 +385,9 @@ __initfunc(void ide_init_hpt34x (ide_hwif_t *hwif)) pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); #ifdef CONFIG_BLK_DEV_HPT34X_DMA +#if 0 hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; +#endif #endif /* CONFIG_BLK_DEV_HPT34X_DMA */ hwif->dmaproc = &hpt34x_dmaproc; } else { diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c new file mode 100644 index 000000000..b61f71687 --- /dev/null +++ b/drivers/block/hpt366.c @@ -0,0 +1,490 @@ +/* + * linux/drivers/block/hpt366.c Version 0.12 August 16, 1999 + * + * Copyright (C) 1999 Andre Hedrick <andre@suse.com> + * + * drive_number + * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/blkdev.h> +#include <linux/hdreg.h> + +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include "ide_modes.h" + +const char *bad_ata66_4[] = { + "WDC AC310200R", + NULL +}; + +const char *bad_ata66_3[] = { + "WDC AC310200R", + NULL +}; + +const char *bad_ata33[] = { + "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", + "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", + "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", + "Maxtor 90510D4", + "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", + "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", + "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", + NULL +}; + +struct chipset_bus_clock_list_entry { + byte xfer_speed; + unsigned int chipset_settings; +}; + +struct chipset_bus_clock_list_entry forty_base [] = { + + { XFER_UDMA_4 , 0x900fd943 }, + { XFER_UDMA_3 , 0x900ad943 }, + { XFER_UDMA_2 , 0x900bd943 }, + { XFER_UDMA_1 , 0x9008d943 }, + { XFER_UDMA_0 , 0x9008d943 }, + + { XFER_MW_DMA_2 , 0xa008d943 }, + { XFER_MW_DMA_1 , 0xa010d955 }, + { XFER_MW_DMA_0 , 0xa010d9fc }, + + { XFER_PIO_4 , 0xc008d963 }, + { XFER_PIO_3 , 0xc010d974 }, + { XFER_PIO_2 , 0xc010d997 }, + { XFER_PIO_1 , 0xc010d9c7 }, + { XFER_PIO_0 , 0xc018d9d9 }, + { 0 , 0x0120d9d9 } +}; + +struct chipset_bus_clock_list_entry thirty_three_base [] = { + + { XFER_UDMA_4 , 0x90c9a731 }, + { XFER_UDMA_3 , 0x90cfa731 }, + { XFER_UDMA_2 , 0x90caa731 }, + { XFER_UDMA_1 , 0x90cba731 }, + { XFER_UDMA_0 , 0x90c8a731 }, + + { XFER_MW_DMA_2 , 0xa0c8a731 }, + { XFER_MW_DMA_1 , 0xa0c8a732 }, /* 0xa0c8a733 */ + { XFER_MW_DMA_0 , 0xa0c8a797 }, + + { XFER_PIO_4 , 0xc0c8a731 }, + { XFER_PIO_3 , 0xc0c8a742 }, + { XFER_PIO_2 , 0xc0d0a753 }, + { XFER_PIO_1 , 0xc0d0a7a3 }, /* 0xc0d0a793 */ + { XFER_PIO_0 , 0xc0d0a7aa }, /* 0xc0d0a7a7 */ + { 0 , 0x0120a7a7 } +}; + +struct chipset_bus_clock_list_entry twenty_five_base [] = { + + { XFER_UDMA_4 , 0x90c98521 }, + { XFER_UDMA_3 , 0x90cf8521 }, + { XFER_UDMA_2 , 0x90cf8521 }, + { XFER_UDMA_1 , 0x90cb8521 }, + { XFER_UDMA_0 , 0x90cb8521 }, + + { XFER_MW_DMA_2 , 0xa0ca8521 }, + { XFER_MW_DMA_1 , 0xa0ca8532 }, + { XFER_MW_DMA_0 , 0xa0ca8575 }, + + { XFER_PIO_4 , 0xc0ca8521 }, + { XFER_PIO_3 , 0xc0ca8532 }, + { XFER_PIO_2 , 0xc0ca8542 }, + { XFER_PIO_1 , 0xc0d08572 }, + { XFER_PIO_0 , 0xc0d08585 }, + { 0 , 0x01208585 } +}; + +#define HPT366_DEBUG_DRIVE_INFO 0 +#define HPT366_ALLOW_ATA66_4 0 +#define HPT366_ALLOW_ATA66_3 1 +#define HPT366_ALLOW_ATA33_2 1 +#define HPT366_ALLOW_ATA33_1 1 +#define HPT366_ALLOW_ATA33_0 1 + +extern char *ide_xfer_verbose (byte xfer_rate); + +static int check_in_drive_lists (ide_drive_t *drive, const char **list) +{ + struct hd_driveid *id = drive->id; + + while (*list) { + if (!strcmp(*list++,id->model)) { +#ifdef DEBUG + printk("%s: Broken ASIC, BackSpeeding (U)DMA for %s\n", drive->name, id->model); +#endif /* DEBUG */ + return 1; + } + } + return 0; +} + +static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) + return chipset_table->chipset_settings; + return 0x01208585; +} + +static int hpt366_tune_chipset (ide_drive_t *drive, byte speed) +{ + int err; + byte busclock; + +#if HPT366_DEBUG_DRIVE_INFO + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + byte regtime = (drive->select.b.unit & 0x01) ? 0x43 : 0x40; + unsigned int reg1 = 0; + unsigned int reg2 = 0; + + pci_read_config_dword(HWIF(drive)->pci_dev, regtime, ®1); + pci_read_config_byte(HWIF(drive)->pci_dev, regtime|0x01, &busclock); + switch(busclock) { + case 0xd9: + reg2 = pci_bus_clock_list(speed, forty_base); + break; + case 0x85: + reg2 = pci_bus_clock_list(speed, twenty_five_base); + break; + case 0xa7: + default: + reg2 = pci_bus_clock_list(speed, thirty_three_base); + break; + } + + if (drive->id->dword_io & 1) + reg2 |= 0x80000000; + else + reg2 &= ~0x80000000; + + pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2); + err = ide_config_drive_speed(drive, speed); + +#if HPT366_DEBUG_DRIVE_INFO + printk("%s: %s drive%d (0x%08x 0x%08x) 0x%04x\n", + drive->name, ide_xfer_verbose(speed), + drive_number, reg1, reg2, err); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + return(err); +} + +/* + * This allows the configuration of ide_pci chipset registers + * for cards that learn about the drive's UDMA, DMA, PIO capabilities + * after the drive is reported by the OS. Initally for designed for + * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc. + * + * check_in_drive_lists(drive, bad_ata66_4) + * check_in_drive_lists(drive, bad_ata66_3) + * check_in_drive_lists(drive, bad_ata33) + * + */ +static int config_chipset_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte speed = 0x00; + + if ((id->dma_ultra & 0x0010) && + (!check_in_drive_lists(drive, bad_ata66_4)) && + (HPT366_ALLOW_ATA66_4) && + (HWIF(drive)->udma_four)) { + if (!((id->dma_ultra >> 8) & 16)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x1010; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && + (!check_in_drive_lists(drive, bad_ata66_3)) && + (HPT366_ALLOW_ATA66_3) && + (HWIF(drive)->udma_four)) { + if (!((id->dma_ultra >> 8) & 8)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0808; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && + (HPT366_ALLOW_ATA33_2) && + (!check_in_drive_lists(drive, bad_ata33))) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && + (HPT366_ALLOW_ATA33_1) && + (!check_in_drive_lists(drive, bad_ata33))) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && + (HPT366_ALLOW_ATA33_0) && + (!check_in_drive_lists(drive, bad_ata33))) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + (void) hpt366_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static void config_chipset_for_pio (ide_drive_t *drive) +{ + unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + + byte timing, speed, pio; + + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + xfer_pio = 0; + + if (drive->id->eide_pio_iordy > 0) { + for (xfer_pio = 5; + xfer_pio>0 && + drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + xfer_pio--); + } else { + xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : + (drive->id->eide_pio_modes & 2) ? 0x04 : + (drive->id->eide_pio_modes & 1) ? 0x03 : + (drive->id->tPIO & 2) ? 0x02 : + (drive->id->tPIO & 1) ? 0x01 : xfer_pio; + } + + timing = (xfer_pio >= pio) ? xfer_pio : pio; + + switch(timing) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: + speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; + break; + } + (void) hpt366_tune_chipset(drive, speed); +} + +static void hpt366_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + switch(pio) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: speed = XFER_PIO_0;break; + } + (void) hpt366_tune_chipset(drive, speed); +} + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + + config_chipset_for_pio(drive); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + * + * This is specific to the HPT366 UDMA bios chipset + * by HighPoint|Triones Technologies, Inc. + */ + +int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + byte reg50h = 0, reg52h = 0; + + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); +#if 0 + case ide_dma_lostirq: + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_lostirq) reg52h=0x%02x\n", drive->name, reg52h); + break; + case ide_dma_timeout: + (void) ide_dmaproc(ide_dma_off_quietly, drive); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_timeout) reg52h=0x%02x\n", drive->name, reg52h); + if (reg52h & 0x04) { + pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0xff); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h); + } + pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); + pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); + printk("%s: (ide_dma_timeout) reg50h=0x%02x reg52h=0x%02x :: again\n", drive->name, reg50h, reg52h); + (void) ide_dmaproc(ide_dma_on, drive); + if (reg52h & 0x04) + (void) ide_dmaproc(ide_dma_off, drive); + return 1; +#endif + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) +{ + byte ata66 = 0; + + pci_read_config_byte(dev, 0x5a, &ata66); + if (dev->resource[PCI_ROM_RESOURCE].start) + pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn)); + return dev->irq; +} + +void __init ide_init_hpt366 (ide_hwif_t *hwif) +{ + hwif->tuneproc = &hpt366_tune_drive; + if (hwif->dma_base) { + byte ata66 = 0; + + hwif->dmaproc = &hpt366_dmaproc; + pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66); + hwif->udma_four = (ata66 & 0x02) ? 0 : 1; + } else { + hwif->udma_four = 0; + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } +} diff --git a/drivers/block/icside.c b/drivers/block/icside.c index edffa0cf1..629ad927d 100644 --- a/drivers/block/icside.c +++ b/drivers/block/icside.c @@ -299,24 +299,7 @@ icside_config_drive(ide_drive_t *drive, int mode) drive->drive_data = 250; } -#if 1 err = ide_config_drive_speed(drive, (byte) speed); -#else - /* - * Don't use ide_wait_cmd here - it will - * attempt to set_geometry and recalibrate, - * but for some reason these don't work at - * this point (lost interrupt). - */ - SELECT_DRIVE(hwif, drive); - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); - OUT_BYTE(speed, IDE_NSECTOR_REG); - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - - err = ide_wait_stat(drive, DRIVE_READY, - BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); -#endif if (err == 0) { drive->id->dma_mword &= 0x00ff; diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 3d338c573..b3ba03562 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -2,7 +2,7 @@ * linux/drivers/block/ide-cd.c * Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov> * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1998, 1999 Jens Axboe <axboe@image.dk> * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -12,11 +12,13 @@ * * Suggestions are welcome. Patches that work are more welcome though. ;-) * For those wishing to work on this driver, please be sure you download - * and comply with the latest ATAPI standard. This document can be - * obtained by anonymous ftp from: - * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps + * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI + * (SFF-8020i rev 2.6) standards. These documents can be obtained by + * anonymous ftp from: + * ftp://fission.dt.wdc.com/pub/standards/SFF/specs/INF-8020.PDF + * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r01.pdf * - * Drives that deviate from the ATAPI standard will be accomodated as much + * Drives that deviate from these standards will be accomodated as much * as possible via compile time or command-line options. Since I only have * a few drives, you generally need to send me patches... * @@ -27,14 +29,8 @@ * This will allow us to get automagically notified when the media changes * on ATAPI drives (something the stock ATAPI spec is lacking). Looks * very cool. I discovered its existance the other day at work... - * -Query the drive to find what features are available before trying to - * use them (like trying to close the tray in drives that can't). * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on * boot - * -Integrate DVD-ROM support in driver. Thanks to Merete Gotsæd-Petersen - * of Pioneer Denmark for providing me with a drive for testing. - * -Implement Features and Profiles. - * * * ---------------------------------- * 1.00 Oct 31, 1994 -- Initial version. @@ -243,11 +239,47 @@ * Useful when using ide-cd in conjunction with * ide-scsi. TODO: non-modular way of doing the * same. - * + * + * 4.54 Aug 5, 1999 - Support for MMC2 class commands through the generic + * packet interface to cdrom.c. + * - Unified audio ioctl support, most of it. + * - cleaned up various deprecated verify_area(). + * - Added ide_cdrom_packet() as the interface for + * the Uniform generic_packet(). + * - bunch of other stuff, will fill in logs later. + * - report 1 slot for non-changers, like the other + * cd-rom drivers. don't report select disc for + * non-changers as well. + * - mask out audio playing, if the device can't do it. + * + * 4.55 Sep 1, 1999 - Eliminated the rest of the audio ioctls, except + * for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers + * use this independently of the actual audio handling. + * They will disappear later when I get the time to + * do it cleanly. + * - Minimize the TOC reading - only do it when we + * know a media change has occured. + * - Moved all the CDROMREADx ioctls to the Uniform layer. + * - Heiko Eissfeldt <heiko@colossus.escape.de> supplied + * some fixes for CDI. + * - CD-ROM leaving door locked fix from Andries + * Brouwer <Andries.Brouwer@cwi.nl> + * - Erik Andersen <andersen@xmission.com> unified + * commands across the various drivers and how + * sense errors are handled. + * + * 4.56 Sep 12, 1999 - Removed changer support - it is now in the + * Uniform layer. + * - Added partition based multisession handling. + * - Mode sense and mode select moved to the + * Uniform layer. + * - Fixed a problem with WPI CDS-32X drive - it + * failed the capabilities + * * *************************************************************************/ - -#define IDECD_VERSION "4.53" + +#define IDECD_VERSION "4.56" #include <linux/config.h> #include <linux/module.h> @@ -304,12 +336,12 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, uses this command to poll the drive, and we don't want to fill the syslog with useless errors. */ if (failed_command && - failed_command->c[0] == SCMD_READ_SUBCHANNEL) + failed_command->c[0] == GPCMD_READ_SUBCHANNEL) return; } if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 - && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || - (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) + && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || + (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) { /* * Suppress the following errors: @@ -346,15 +378,16 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, s = buf; } else { int lo=0, mid, hi=ARY_LEN (sense_data_texts); - unsigned short key = (reqbuf->asc << 8); + unsigned long key = (reqbuf->sense_key << 16); + key |= (reqbuf->asc << 8); if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) key |= reqbuf->ascq; - s = NULL; while (hi > lo) { mid = (lo + hi) / 2; - if (sense_data_texts[mid].asc_ascq == key) { + if (sense_data_texts[mid].asc_ascq == key || + sense_data_texts[mid].asc_ascq == (0xff0000|key)) { s = sense_data_texts[mid].text; break; } @@ -475,7 +508,7 @@ static void cdrom_queue_request_sense (ide_drive_t *drive, len = sizeof (*reqbuf) / 4; len *= 4; - pc->c[0] = REQUEST_SENSE; + pc->c[0] = GPCMD_REQUEST_SENSE; pc->c[4] = (unsigned char) len; pc->buffer = (char *)reqbuf; pc->buflen = len; @@ -517,8 +550,9 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; - int stat, err, sense_key, cmd; - + int stat, cmd, err, sense_key; + struct packet_command *pc = (struct packet_command *) rq->buffer; + /* Check for errors. */ stat = GET_STAT(); *stat_ret = stat; @@ -526,8 +560,8 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, if (OK_STAT (stat, good_stat, BAD_R_STAT)) return 0; - /* Got an error. */ - err = IN_BYTE (IDE_ERROR_REG); + /* Get the IDE error register. */ + err = GET_ERR(); sense_key = err >> 4; if (rq == NULL) @@ -541,8 +575,6 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, from the drive (probably while trying to recover from a former error). Just give up. */ - struct packet_command *pc = (struct packet_command *) - rq->buffer; pc->stat = 1; cdrom_end_request (1, drive); ide_error (drive, "request sense failure", stat); @@ -551,23 +583,11 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, } else if (cmd == PACKET_COMMAND) { /* All other functions, except for READ. */ - struct packet_command *pc = (struct packet_command *) - rq->buffer; struct semaphore *sem = NULL; /* Check for tray open. */ if (sense_key == NOT_READY) { cdrom_saw_media_change (drive); -#if 0 /* let the upper layers do the complaining */ - /* Print an error message to the syslog. - Exception: don't print anything if this - is a read subchannel command. This is - because workman constantly polls the drive - with this command, and we don't want - to uselessly fill up the syslog. */ - if (pc->c[0] != SCMD_READ_SUBCHANNEL) - printk ("%s: tray open or drive not ready\n", drive->name); -#endif } else if (sense_key == UNIT_ATTENTION) { /* Check for media change. */ cdrom_saw_media_change (drive); @@ -1061,7 +1081,7 @@ static void cdrom_start_read_continuation (ide_drive_t *drive) /* Set up the command */ memset (&pc.c, 0, sizeof (pc.c)); - pc.c[0] = READ_10; + pc.c[0] = GPCMD_READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); @@ -1106,7 +1126,7 @@ static void cdrom_start_seek_continuation (ide_drive_t *drive) frame = sector / SECTORS_PER_FRAME; memset (&pc.c, 0, sizeof (pc.c)); - pc.c[0] = SEEK; + pc.c[0] = GPCMD_SEEK; put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr); } @@ -1170,8 +1190,6 @@ static int cdrom_lockdoor (ide_drive_t *drive, int lockflag, struct atapi_request_sense *reqbuf); - - /* Interrupt routine for packet command completion. */ static void cdrom_pc_intr (ide_drive_t *drive) { @@ -1192,7 +1210,7 @@ static void cdrom_pc_intr (ide_drive_t *drive) if ((stat & DRQ_STAT) == 0) { /* Some of the trailing request sense fields are optional, and some drives don't send them. Sigh. */ - if (pc->c[0] == REQUEST_SENSE && + if (pc->c[0] == GPCMD_REQUEST_SENSE && pc->buflen > 0 && pc->buflen <= 5) { while (pc->buflen > 0) { @@ -1219,20 +1237,10 @@ static void cdrom_pc_intr (ide_drive_t *drive) /* Figure out how much data to transfer. */ thislen = pc->buflen; - if (thislen < 0) thislen = -thislen; if (thislen > len) thislen = len; /* The drive wants to be written to. */ if ((ireason & 3) == 0) { - /* Check that we want to write. */ - if (pc->buflen > 0) { - printk ("%s: cdrom_pc_intr: Drive wants " - "to transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } - /* Transfer the data. */ atapi_output_bytes (drive, pc->buffer, thislen); @@ -1246,19 +1254,11 @@ static void cdrom_pc_intr (ide_drive_t *drive) /* Keep count of how much data we've moved. */ pc->buffer += thislen; - pc->buflen += thislen; + pc->buflen -= thislen; } /* Same drill for reading. */ else if ((ireason & 3) == 2) { - /* Check that we want to read. */ - if (pc->buflen < 0) { - printk ("%s: cdrom_pc_intr: Drive wants to " - "transfer data the wrong way!\n", - drive->name); - pc->stat = 1; - thislen = 0; - } /* Transfer the data. */ atapi_input_bytes (drive, pc->buffer, thislen); @@ -1305,11 +1305,8 @@ static void cdrom_do_packet_command (ide_drive_t *drive) struct cdrom_info *info = drive->driver_data; info->dma = 0; - - len = pc->buflen; - if (len < 0) len = -len; - pc->stat = 0; + len = pc->buflen; /* Start sending the command to the drive. */ cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation); @@ -1337,7 +1334,6 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) if (pc->sense_data == NULL) pc->sense_data = &my_reqbuf; pc->sense_data->sense_key = 0; - /* Start of retry loop. */ do { ide_init_drive_cmd (&req); @@ -1362,10 +1358,10 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) a disk. Retry, but wait a little to give the drive time to complete the load. */ cdrom_sleep (HZ); - } else + } else { /* Otherwise, don't retry. */ retries = 0; - + } --retries; } @@ -1379,20 +1375,22 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) else { /* The command succeeded. If it was anything other than a request sense, eject, or door lock command, - and we think that the door is presently, lock it again. - (The door was probably unlocked via an explicit + and we think that the door is presently unlocked, lock it + again. (The door was probably unlocked via an explicit CDROMEJECT ioctl.) */ - if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && drive->usage && - (pc->c[0] != REQUEST_SENSE && - pc->c[0] != ALLOW_MEDIUM_REMOVAL && - pc->c[0] != START_STOP)) { + if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && + (pc->c[0] != GPCMD_TEST_UNIT_READY && + pc->c[0] != GPCMD_REQUEST_SENSE && + pc->c[0] != GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL && + pc->c[0] != GPCMD_START_STOP_UNIT && + pc->c[0] != GPCMD_MODE_SENSE_10 && + pc->c[0] != GPCMD_MODE_SELECT_10)) { (void) cdrom_lockdoor (drive, 1, NULL); } return 0; } } - /**************************************************************************** * cdrom driver request routine. */ @@ -1493,17 +1491,19 @@ cdrom_check_status (ide_drive_t *drive, struct atapi_request_sense *reqbuf) { struct packet_command pc; + struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = TEST_UNIT_READY; + pc.c[0] = GPCMD_TEST_UNIT_READY; #if ! STANDARD_ATAPI /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs instead of supporting the LOAD_UNLOAD opcode */ - pc.c[7] = CDROM_STATE_FLAGS (drive)->sanyo_slot % 3; + pc.c[7] = cdi->sanyo_slot % 3; #endif /* not STANDARD_ATAPI */ return cdrom_queue_packet_command (drive, &pc); @@ -1518,7 +1518,7 @@ cdrom_lockdoor (ide_drive_t *drive, int lockflag, struct atapi_request_sense my_reqbuf; int stat; struct packet_command pc; - + if (reqbuf == NULL) reqbuf = &my_reqbuf; @@ -1529,7 +1529,7 @@ cdrom_lockdoor (ide_drive_t *drive, int lockflag, memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = ALLOW_MEDIUM_REMOVAL; + pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); stat = cdrom_queue_packet_command (drive, &pc); } @@ -1564,45 +1564,18 @@ cdrom_eject (ide_drive_t *drive, int ejectflag, { struct packet_command pc; - if (CDROM_CONFIG_FLAGS (drive)->no_eject==1 && ejectflag==0) + if (CDROM_CONFIG_FLAGS (drive)->no_eject && !ejectflag) return -EDRIVE_CANT_DO_THIS; + + /* reload fails on some drives, if the tray is locked */ + if (CDROM_STATE_FLAGS (drive)->door_locked && ejectflag) + return 0; memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = START_STOP; - pc.c[4] = 2 + (ejectflag != 0); - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_pause (ide_drive_t *drive, int pauseflag, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = SCMD_PAUSE_RESUME; - pc.c[8] = !pauseflag; - return cdrom_queue_packet_command (drive, &pc); -} - - -static int -cdrom_startstop (ide_drive_t *drive, int startflag, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = START_STOP; - pc.c[1] = 1; - pc.c[4] = startflag; + pc.c[0] = GPCMD_START_STOP_UNIT; + pc.c[4] = 0x02 + (ejectflag != 0); return cdrom_queue_packet_command (drive, &pc); } @@ -1611,8 +1584,8 @@ cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, struct atapi_request_sense *reqbuf) { struct { - unsigned lba; - unsigned blocklen; + __u32 lba; + __u32 blocklen; } capbuf; int stat; @@ -1621,7 +1594,7 @@ cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, memset (&pc, 0, sizeof (pc)); pc.sense_data = reqbuf; - pc.c[0] = READ_CAPACITY; + pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; pc.buflen = sizeof (capbuf); @@ -1645,7 +1618,7 @@ cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag, pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = SCMD_READ_TOC; + pc.c[0] = GPCMD_READ_TOC_PMA_ATIP; pc.c[6] = trackno; pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); @@ -1657,12 +1630,12 @@ cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag, /* Try to read the entire TOC for the disk into our internal buffer. */ static int -cdrom_read_toc (ide_drive_t *drive, - struct atapi_request_sense *reqbuf) +cdrom_read_toc (ide_drive_t *drive, struct atapi_request_sense *reqbuf) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; + int minor = drive->select.b.unit << PARTN_BITS; struct { struct atapi_toc_header hdr; struct atapi_toc_entry ent; @@ -1673,11 +1646,10 @@ cdrom_read_toc (ide_drive_t *drive, toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), GFP_KERNEL); info->toc = toc; - } - - if (toc == NULL) { - printk ("%s: No cdrom TOC buffer!\n", drive->name); - return -EIO; + if (toc == NULL) { + printk ("%s: No cdrom TOC buffer!\n", drive->name); + return -ENOMEM; + } } /* Check to see if the existing data is still valid. @@ -1689,9 +1661,7 @@ cdrom_read_toc (ide_drive_t *drive, /* First read just the header, so we know how long the TOC is. */ stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, - sizeof (struct atapi_toc_header) + - sizeof (struct atapi_toc_entry), - reqbuf); + sizeof (struct atapi_toc_header), reqbuf); if (stat) return stat; #if ! STANDARD_ATAPI @@ -1706,12 +1676,46 @@ cdrom_read_toc (ide_drive_t *drive, if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; /* Now read the whole schmeer. */ - stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, + stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + - (ntracks+1) * - sizeof (struct atapi_toc_entry), - reqbuf); + (ntracks + 1) * + sizeof (struct atapi_toc_entry), reqbuf); + + if (stat && toc->hdr.first_track > 1) { + /* Cds with CDI tracks only don't have any TOC entries, + despite of this the returned values are + first_track == last_track = number of CDI tracks + 1, + so that this case is indistinguishable from the same + layout plus an additional audio track. + If we get an error for the regular case, we assume + a CDI without additional audio tracks. In this case + the readable TOC is empty (CDI tracks are not included) + and only holds the Leadout entry. Heiko Eißfeldt */ + ntracks = 0; + stat = cdrom_read_tocentry (drive, CDROM_LEADOUT, 1, + 0, (char *)&toc->hdr, + sizeof (struct atapi_toc_header) + + (ntracks+1) * + sizeof (struct atapi_toc_entry), + reqbuf); + if (stat) { + return stat; + } +#if ! STANDARD_ATAPI + if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) { + toc->hdr.first_track = bin2bcd(CDROM_LEADOUT); + toc->hdr.last_track = bin2bcd(CDROM_LEADOUT); + } else +#endif /* not STANDARD_ATAPI */ + { + toc->hdr.first_track = CDROM_LEADOUT; + toc->hdr.last_track = CDROM_LEADOUT; + } + } else if (stat) { + return stat; + } if (stat) return stat; + toc->hdr.toc_length = ntohs (toc->hdr.toc_length); #if ! STANDARD_ATAPI @@ -1735,10 +1739,18 @@ cdrom_read_toc (ide_drive_t *drive, } /* Read the multisession information. */ - stat = cdrom_read_tocentry (drive, 0, 1, 1, - (char *)&ms_tmp, sizeof (ms_tmp), - reqbuf); - if (stat) return stat; + if (toc->hdr.first_track != CDROM_LEADOUT) { + /* Read the multisession information. */ + stat = cdrom_read_tocentry (drive, 0, 1, 1, + (char *)&ms_tmp, sizeof (ms_tmp), + reqbuf); + if (stat) return stat; + } else { + ms_tmp.ent.addr.msf.minute = 0; + ms_tmp.ent.addr.msf.second = 2; + ms_tmp.ent.addr.msf.frame = 0; + ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT; + } #if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) @@ -1752,16 +1764,39 @@ cdrom_read_toc (ide_drive_t *drive, toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); /* Now try to get the total cdrom capacity. */ +#if 0 + stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major, minor, + (long *)&toc->capacity); + if (stat) +#endif stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf); if (stat) toc->capacity = 0x1fffff; - HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] - = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); - drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; + /* for general /dev/cdrom like mounting, one big disc */ + HWIF(drive)->gd->sizes[minor] = (toc->capacity * SECTORS_PER_FRAME) >> + (BLOCK_SIZE_BITS - 9); /* Remember that we've read this stuff. */ CDROM_STATE_FLAGS (drive)->toc_valid = 1; + /* should be "if multisession", but it does no harm. */ + if (ntracks == 1) + return 0; + + /* setup each minor to respond to a session */ + minor++; + i = toc->hdr.first_track; + while ((i <= ntracks) && ((minor & CD_PART_MASK) < CD_PART_MAX)) { + drive->part[minor & PARTN_MASK].start_sect = 0; + drive->part[minor & PARTN_MASK].nr_sects = (toc->ent[i].addr.lba * + SECTORS_PER_FRAME) << (BLOCK_SIZE_BITS - 9); + HWIF(drive)->gd->sizes[minor] = (toc->ent[i].addr.lba * + SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); + blksize_size[HWIF(drive)->major][minor] = CD_FRAMESIZE; + i++; + minor++; + } + return 0; } @@ -1778,7 +1813,7 @@ cdrom_read_subchannel (ide_drive_t *drive, int format, pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = SCMD_READ_SUBCHANNEL; + pc.c[0] = GPCMD_READ_SUBCHANNEL; pc.c[1] = 2; /* MSF addressing */ pc.c[2] = 0x40; /* request subQ data */ pc.c[3] = format; @@ -1787,46 +1822,6 @@ cdrom_read_subchannel (ide_drive_t *drive, int format, return cdrom_queue_packet_command (drive, &pc); } - -/* modeflag: 0 = current, 1 = changeable mask, 2 = default, 3 = saved */ -static int -cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - pc.c[0] = MODE_SENSE_10; - pc.c[2] = pageno | (modeflag << 6); - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); -} - -static int -cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = - buflen; - pc.c[0] = MODE_SELECT_10; - pc.c[1] = 0x10; - pc.c[2] = pageno; - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); -} - /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ static int @@ -1842,7 +1837,7 @@ cdrom_select_speed (ide_drive_t *drive, int speed, else speed *= 177; /* Nx to kbytes/s */ - pc.c[0] = SET_CD_SPEED; + pc.c[0] = GPCMD_SET_SPEED; /* Read Drive speed in kbytes/second MSB */ pc.c[2] = (speed >> 8) & 0xff; /* Read Drive speed in kbytes/second LSB */ @@ -1858,67 +1853,6 @@ cdrom_select_speed (ide_drive_t *drive, int speed, return cdrom_queue_packet_command (drive, &pc); } -static int -cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = SCMD_PLAYAUDIO_MSF; - lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); - lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]); - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd) { - pc.c[3] = bin2bcd (pc.c[3]); - pc.c[4] = bin2bcd (pc.c[4]); - pc.c[5] = bin2bcd (pc.c[5]); - pc.c[6] = bin2bcd (pc.c[6]); - pc.c[7] = bin2bcd (pc.c[7]); - pc.c[8] = bin2bcd (pc.c[8]); - } -#endif /* not STANDARD_ATAPI */ - - return cdrom_queue_packet_command (drive, &pc); -} - - -/* Play audio starting at LBA LBA_START and finishing with the - LBA before LBA_END. */ -static int -cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end, - struct atapi_request_sense *reqbuf) -{ - int i, stat; - struct atapi_request_sense my_reqbuf; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - /* Some drives, will, for certain audio cds, - give an error if you ask them to play the entire cd using the - values which are returned in the TOC. The play will succeed, - however, if the ending address is adjusted downwards - by a few frames. */ - for (i=0; i<75; i++) { - stat = cdrom_play_lba_range_1 (drive, lba_start, lba_end, - reqbuf); - - if (stat == 0 || - !(reqbuf->sense_key == ILLEGAL_REQUEST && - reqbuf->asc == 0x24)) - return stat; - - --lba_end; - if (lba_end <= lba_start) break; - } - - return stat; -} - static int cdrom_get_toc_entry (ide_drive_t *drive, int track, @@ -1926,17 +1860,12 @@ int cdrom_get_toc_entry (ide_drive_t *drive, int track, struct atapi_request_sense *reqbuf) { struct cdrom_info *info = drive->driver_data; - int stat, ntracks; - struct atapi_toc *toc; - - /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc (drive, reqbuf); - if (stat) return stat; - - toc = info->toc; + struct atapi_toc *toc = info->toc; + int ntracks; /* Check validity of requested track number. */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; + if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0; if (track == CDROM_LEADOUT) *ent = &toc->ent[ntracks]; else if (track < toc->hdr.first_track || @@ -1949,86 +1878,6 @@ int cdrom_get_toc_entry (ide_drive_t *drive, int track, } -static int -cdrom_read_block (ide_drive_t *drive, int format, int lba, int nblocks, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - struct atapi_request_sense my_reqbuf; - - if (reqbuf == NULL) - reqbuf = &my_reqbuf; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->nec260) - pc.c[0] = 0xd4; - else -#endif /* not STANDARD_ATAPI */ - pc.c[0] = READ_CD; - - pc.c[1] = (format << 2); - put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]); - pc.c[8] = (nblocks & 0xff); - pc.c[7] = ((nblocks>>8) & 0xff); - pc.c[6] = ((nblocks>>16) & 0xff); - if (format <= 1) - pc.c[9] = 0xf8; /* returns 2352 for any format */ - else - pc.c[9] = 0x10; - - return cdrom_queue_packet_command (drive, &pc); -} - - -/* If SLOT<0, unload the current slot. Otherwise, try to load SLOT. */ -static int -cdrom_load_unload (ide_drive_t *drive, int slot, - struct atapi_request_sense *reqbuf) -{ -#if ! STANDARD_ATAPI - /* if the drive is a Sanyo 3 CD changer then TEST_UNIT_READY - (used in the cdrom_check_status function) is used to - switch CDs instead of LOAD_UNLOAD */ - - if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { - - if ((slot == 1) || (slot == 2)) - CDROM_STATE_FLAGS (drive)->sanyo_slot = slot; - else if (slot >= 0) - CDROM_STATE_FLAGS (drive)->sanyo_slot = 3; - else - return 0; - - return cdrom_check_status (drive, reqbuf); - - } - else -#endif /*not STANDARD_ATAPI */ - { - - /* ATAPI Rev. 2.2+ standard for requesting switching of - CDs in a multiplatter device */ - - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.c[0] = LOAD_UNLOAD; - pc.c[4] = 2 + (slot >= 0); - pc.c[8] = slot; - return cdrom_queue_packet_command (drive, &pc); - - } -} - /* This gets the mechanism status per ATAPI draft spec 2.6 */ static int @@ -2042,13 +1891,12 @@ cdrom_read_mech_status (ide_drive_t *drive, char *buf, int buflen, pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = MECHANISM_STATUS; + pc.c[0] = GPCMD_MECHANISM_STATUS; pc.c[8] = (buflen >> 8); pc.c[9] = (buflen & 0xff); return cdrom_queue_packet_command (drive, &pc); } - /* Read the drive mechanism status and slot table into our internal buffer. If the buffer does not yet exist, allocate it. */ static int @@ -2090,231 +1938,70 @@ cdrom_read_changer_info (ide_drive_t *drive) NULL); } +/* the generic packet interface to cdrom.c */ +static int ide_cdrom_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + struct packet_command pc; + ide_drive_t *drive = (ide_drive_t*) cdi->handle; + + /* here we queue the commands from the uniform CD-ROM + layer. the packet must be complete, as we do not + touch it at all. */ + memset(&pc, 0, sizeof(pc)); + memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); + pc.buffer = cgc->buffer; + pc.buflen = cgc->buflen; + cgc->stat = cdrom_queue_packet_command(drive, &pc); + return cgc->stat; +} static int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) - { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; + struct cdrom_generic_command cgc; + char buffer[16]; + int stat; + init_cdrom_command(&cgc, buffer, sizeof(buffer)); + /* These will be moved into the Uniform layer shortly... */ switch (cmd) { - case CDROMREADRAW: - case CDROMREADMODE1: - case CDROMREADMODE2: { - struct cdrom_msf msf; - int blocksize, format, stat, lba; - struct atapi_toc *toc; - char *buf; - - if (cmd == CDROMREADMODE1) { - blocksize = CD_FRAMESIZE; - format = 2; - } else { /* for RAW and MODE2. */ - blocksize = CD_FRAMESIZE_RAW; - format = 0; - } - - copy_from_user_ret(&msf, (void *)arg, sizeof (msf), -EFAULT); - - lba = msf_to_lba(msf.cdmsf_min0, - msf.cdmsf_sec0, - msf.cdmsf_frame0); - - /* Make sure the TOC is up to date. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - - toc = info->toc; - - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; - - buf = (char *) kmalloc (blocksize, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize, - NULL); - - if (stat == 0) { - if (cmd == CDROMREADMODE2) { - /* For Mode2, skip the Sync, Header, and Subheader */ - copy_to_user_ret((char *)arg, buf+16, CD_FRAMESIZE_RAW0, -EFAULT); - } else { - copy_to_user_ret((char *)arg, buf, blocksize, -EFAULT); - } - } - - kfree (buf); - return stat; - } - - /* Read 2352 byte blocks from audio tracks. */ - case CDROMREADAUDIO: { - int stat, lba; - struct atapi_toc *toc; - struct cdrom_read_audio ra; - char *buf; - - /* Make sure the TOC is up to date. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - - toc = info->toc; - - stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra)); - if (stat) return stat; - - copy_from_user (&ra, (void *)arg, sizeof (ra)); - - if (ra.nframes < 0 || ra.nframes > toc->capacity) - return -EINVAL; - else if (ra.nframes == 0) - return 0; - - stat = verify_area (VERIFY_WRITE, (char *)ra.buf, - ra.nframes * CD_FRAMESIZE_RAW); - if (stat) return stat; - - if (ra.addr_format == CDROM_MSF) - lba = msf_to_lba (ra.addr.msf.minute, - ra.addr.msf.second, - ra.addr.msf.frame); - else if (ra.addr_format == CDROM_LBA) - lba = ra.addr.lba; - else - return -EINVAL; - - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; - - buf = (char *) kmalloc (CDROM_NBLOCKS_BUFFER*CD_FRAMESIZE_RAW, - GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - while (ra.nframes > 0) { - int this_nblocks = ra.nframes; - if (this_nblocks > CDROM_NBLOCKS_BUFFER) - this_nblocks = CDROM_NBLOCKS_BUFFER; - stat = cdrom_read_block - (drive, 1, lba, this_nblocks, - buf, this_nblocks * CD_FRAMESIZE_RAW, NULL); - if (stat) break; - - copy_to_user (ra.buf, buf, - this_nblocks * CD_FRAMESIZE_RAW); - ra.buf += this_nblocks * CD_FRAMESIZE_RAW; - ra.nframes -= this_nblocks; - lba += this_nblocks; - } - - kfree (buf); - return stat; - } - case CDROMSETSPINDOWN: { char spindown; - char buffer[16]; - int stat; - - stat = verify_area (VERIFY_READ, (void *) arg, - sizeof (char)); - if (stat) return stat; - copy_from_user (&spindown, (void *) arg, sizeof(char)); + if (copy_from_user(&spindown, (void *) arg, sizeof(char))) + return -EFAULT; - stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; + if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0))) + return stat; buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f); - return cdrom_mode_select (drive, PAGE_CDROM, buffer, - sizeof (buffer), NULL); + return cdrom_mode_select(cdi, &cgc); } case CDROMGETSPINDOWN: { char spindown; - char buffer[16]; - int stat; - - stat = verify_area (VERIFY_WRITE, (void *) arg, - sizeof (char)); - if (stat) return stat; - stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; + if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0))) + return stat; spindown = buffer[11] & 0x0f; - copy_to_user ((void *) arg, &spindown, sizeof (char)); + if (copy_to_user((void *) arg, &spindown, sizeof (char))) + return -EFAULT; return 0; } -#ifdef ALLOW_TEST_PACKETS - case 0x1234: { - int stat; - struct packet_command pc; - int len, lena; - - memset (&pc, 0, sizeof (pc)); - - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (pc.c)); - if (stat) return stat; - copy_from_user (&pc.c, (void *) arg, sizeof (pc.c)); - arg += sizeof (pc.c); - - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len)); - if (stat) return stat; - copy_from_user (&len, (void *) arg , sizeof (len)); - arg += sizeof (len); - - lena = len; - if (lena < 0) lena = -lena; - - { - char buf[lena]; - if (len > 0) { - stat = verify_area (VERIFY_WRITE, - (void *) arg, len); - if (stat) return stat; - } - else if (len < 0) { - stat = verify_area (VERIFY_READ, - (void *) arg, -len); - if (stat) return stat; - copy_from_user (buf, (void*)arg, -len); - } - - if (len != 0) { - pc.buflen = len; - pc.buffer = buf; - } - - stat = cdrom_queue_packet_command (drive, &pc); - - if (len > 0) - copy_to_user ((void *)arg, buf, len); - } - - return stat; - } -#endif - default: return -EINVAL; } } - - static int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, unsigned int cmd, void *arg) @@ -2324,47 +2011,6 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, struct cdrom_info *info = drive->driver_data; switch (cmd) { - case CDROMSUBCHNL: { - struct atapi_cdrom_subchnl scbuf; - int stat; - struct cdrom_subchnl *subchnl = (struct cdrom_subchnl *)arg; - - stat = cdrom_read_subchannel (drive, 1, /* current position */ - (char *)&scbuf, sizeof (scbuf), - NULL); - if (stat) return stat; - -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd) { - msf_from_bcd (&scbuf.acdsc_absaddr.msf); - msf_from_bcd (&scbuf.acdsc_reladdr.msf); - } - if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) - scbuf.acdsc_trk = bcd2bin (scbuf.acdsc_trk); -#endif /* not STANDARD_ATAPI */ - - subchnl->cdsc_absaddr.msf.minute = - scbuf.acdsc_absaddr.msf.minute; - subchnl->cdsc_absaddr.msf.second = - scbuf.acdsc_absaddr.msf.second; - subchnl->cdsc_absaddr.msf.frame = - scbuf.acdsc_absaddr.msf.frame; - - subchnl->cdsc_reladdr.msf.minute = - scbuf.acdsc_reladdr.msf.minute; - subchnl->cdsc_reladdr.msf.second = - scbuf.acdsc_reladdr.msf.second; - subchnl->cdsc_reladdr.msf.frame = - scbuf.acdsc_reladdr.msf.frame; - - subchnl->cdsc_audiostatus = scbuf.acdsc_audiostatus; - subchnl->cdsc_ctrl = scbuf.acdsc_ctrl; - subchnl->cdsc_trk = scbuf.acdsc_trk; - subchnl->cdsc_ind = scbuf.acdsc_ind; - - return 0; - } - case CDROMREADTOCHDR: { int stat; struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; @@ -2392,119 +2038,22 @@ int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, tocentry->cdte_ctrl = toce->control; tocentry->cdte_adr = toce->adr; - tocentry->cdte_format = CDROM_LBA; - tocentry->cdte_addr.lba = toce->addr.lba; - - return 0; - } - - case CDROMPLAYMSF: { - struct cdrom_msf *msf = (struct cdrom_msf *) arg; - int lba_start, lba_end; - - lba_start = msf_to_lba (msf->cdmsf_min0, msf->cdmsf_sec0, - msf->cdmsf_frame0); - lba_end = msf_to_lba (msf->cdmsf_min1, msf->cdmsf_sec1, - msf->cdmsf_frame1) + 1; - - if (lba_end <= lba_start) return -EINVAL; - - return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); - } - - /* Like just about every other Linux cdrom driver, we ignore the - index part of the request here. */ - case CDROMPLAYTRKIND: { - int stat, lba_start, lba_end; - struct cdrom_ti *ti = (struct cdrom_ti *)arg; - struct atapi_toc_entry *first_toc, *last_toc; - - stat = cdrom_get_toc_entry (drive, ti->cdti_trk0, &first_toc, - NULL); - if (stat) return stat; - stat = cdrom_get_toc_entry (drive, ti->cdti_trk1, &last_toc, - NULL); - if (stat) return stat; - - if (ti->cdti_trk1 != CDROM_LEADOUT) ++last_toc; - lba_start = first_toc->addr.lba; - lba_end = last_toc->addr.lba; - - if (lba_end <= lba_start) return -EINVAL; - - return cdrom_play_lba_range (drive, lba_start, lba_end, NULL); - } - - case CDROMVOLCTRL: { - struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg; - char buffer[24], mask[24]; - int stat; - - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 1, mask, - sizeof (buffer), NULL); - if (stat) return stat; - - buffer[1] = buffer[2] = 0; - - buffer[17] = volctrl->channel0 & mask[17]; - buffer[19] = volctrl->channel1 & mask[19]; - buffer[21] = volctrl->channel2 & mask[21]; - buffer[23] = volctrl->channel3 & mask[23]; - - return cdrom_mode_select (drive, PAGE_AUDIO, buffer, - sizeof (buffer), NULL); - } - - case CDROMVOLREAD: { - struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg; - char buffer[24]; - int stat; - - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; - - volctrl->channel0 = buffer[17]; - volctrl->channel1 = buffer[19]; - volctrl->channel2 = buffer[21]; - volctrl->channel3 = buffer[23]; + if (tocentry->cdte_format == CDROM_MSF) { + lba_to_msf (toce->addr.lba, + &tocentry->cdte_addr.msf.minute, + &tocentry->cdte_addr.msf.second, + &tocentry->cdte_addr.msf.frame); + } else + tocentry->cdte_addr.lba = toce->addr.lba; return 0; } - case CDROMSTART: - return cdrom_startstop (drive, 1, NULL); - - case CDROMSTOP: { -#ifdef IHAVEADOLPHIN - /* Certain Drives require this. Most don't - and will produce errors upon CDROMSTOP - pit says the Dolphin needs this. If you - own a dolphin, just define IHAVEADOLPHIN somewhere */ - int stat; - stat = cdrom_startstop (drive, 0, NULL); - if (stat) return stat; - return cdrom_eject (drive, 1, NULL); -#endif /* end of IHAVEADOLPHIN */ - return cdrom_startstop (drive, 0, NULL); - } - - case CDROMPAUSE: - return cdrom_pause (drive, 1, NULL); - - case CDROMRESUME: - return cdrom_pause (drive, 0, NULL); - - default: return -EINVAL; } } - static int ide_cdrom_reset (struct cdrom_device_info *cdi) { @@ -2531,7 +2080,6 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) return cdrom_eject (drive, !position, NULL); } - static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { @@ -2543,22 +2091,23 @@ static int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) { int stat, attempts = 3; - struct { - char pad[8]; - struct atapi_capabilities_page cap; - } buf; ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct atapi_request_sense reqbuf; + struct cdrom_generic_command cgc; + struct { + char pad[8]; + struct atapi_capabilities_page cap; + } buf; stat=cdrom_select_speed (drive, speed, &reqbuf); if (stat<0) return stat; + init_cdrom_command(&cgc, &buf, sizeof(buf)); /* Now with that done, update the speed fields */ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ if (attempts-- <= 0) return 0; - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, - (char *)&buf, sizeof (buf), NULL); + stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); } while (stat); /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ @@ -2577,93 +2126,6 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) return 0; } - -static -int ide_cdrom_select_disc (struct cdrom_device_info *cdi, int slot) -{ - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; - - struct atapi_request_sense my_reqbuf; - int stat; - int nslots, curslot; - - if ( ! CDROM_CONFIG_FLAGS (drive)->is_changer) - return -EDRIVE_CANT_DO_THIS; - -#if ! STANDARD_ATAPI - if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { - nslots = 3; - curslot = CDROM_STATE_FLAGS (drive)->sanyo_slot; - if (curslot == 3) - curslot = 0; - } else -#endif /* not STANDARD_ATAPI */ - { - stat = cdrom_read_changer_info (drive); - if (stat) - return stat; - - nslots = info->changer_info->hdr.nslots; - curslot = info->changer_info->hdr.curslot; - } - - if (slot == curslot) - return curslot; - - if (slot == CDSL_CURRENT) - return curslot; - - if (slot != CDSL_NONE && (slot < 0 || slot >= nslots)) - return -EINVAL; - - if (drive->usage > 1) - return -EBUSY; - - if (slot == CDSL_NONE) { - (void) cdrom_load_unload (drive, -1, NULL); - cdrom_saw_media_change (drive); - (void) cdrom_lockdoor (drive, 0, NULL); - return 0; - } - else { - int was_locked; - - if ( -#if ! STANDARD_ATAPI - CDROM_STATE_FLAGS (drive)->sanyo_slot == 0 && -#endif - info->changer_info->slots[slot].disc_present == 0) { - return -ENOMEDIUM; - } - - was_locked = CDROM_STATE_FLAGS (drive)->door_locked; - if (was_locked) - (void) cdrom_lockdoor (drive, 0, NULL); - - stat = cdrom_load_unload (drive, slot, NULL); - cdrom_saw_media_change (drive); - if (stat) - return stat; - - stat = cdrom_check_status (drive, &my_reqbuf); - if (stat && my_reqbuf.sense_key == NOT_READY) - return -ENOENT; - - if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) { - stat = cdrom_read_toc (drive, &my_reqbuf); - if (stat) - return stat; - } - - if (was_locked) - (void) cdrom_lockdoor (drive, 1, NULL); - - return slot; - } -} - - static int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { @@ -2688,7 +2150,7 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) } #if ! STANDARD_ATAPI - else if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) + else if (cdi->sanyo_slot > 0) return CDS_NO_INFO; #endif /* not STANDARD_ATAPI */ @@ -2710,15 +2172,10 @@ static int ide_cdrom_get_last_session (struct cdrom_device_info *cdi, struct cdrom_multisession *ms_info) { - int stat; struct atapi_toc *toc; ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct cdrom_info *info = drive->driver_data; - /* Make sure the TOC information is valid. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; - toc = info->toc; ms_info->addr.lba = toc->last_session_lba; ms_info->xa_flag = toc->xa_flag; @@ -2726,7 +2183,6 @@ int ide_cdrom_get_last_session (struct cdrom_device_info *cdi, return 0; } - static int ide_cdrom_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn_info) @@ -2760,9 +2216,9 @@ int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi, { ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct cdrom_info *info = drive->driver_data; - + struct atapi_request_sense reqbuf; int retval; - + if (slot_nr == CDSL_CURRENT) { (void) cdrom_check_status (drive, NULL); retval = CDROM_STATE_FLAGS (drive)->media_changed; @@ -2770,7 +2226,7 @@ int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi, } #if ! STANDARD_ATAPI - else if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { + else if (cdi->sanyo_slot > 0) { retval = 0; } #endif /* not STANDARD_ATAPI */ @@ -2788,7 +2244,17 @@ int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi, retval = ci->slots[slot_nr].change; } - + + /* if the media has changed, check if a disc is in the drive + and read the toc info. */ + if (retval || !CDROM_STATE_FLAGS (drive)->toc_valid) { + /* if cdrom_read_toc fails, return 1 to indicate + that a disc change has occured. there might not + be a disc in the drive. */ + if ((retval = cdrom_read_toc (drive, &reqbuf))) + return 1; + } + return retval; } @@ -2824,7 +2290,7 @@ struct cdrom_device_ops ide_cdrom_dops = { ide_cdrom_tray_move, /* tray_move */ ide_cdrom_lock_door, /* lock_door */ ide_cdrom_select_speed, /* select_speed */ - ide_cdrom_select_disc, /* select_disc */ + NULL, /* select_disc */ ide_cdrom_get_last_session, /* get_last_session */ ide_cdrom_get_mcn, /* get_mcn */ ide_cdrom_reset, /* reset */ @@ -2832,9 +2298,11 @@ struct cdrom_device_ops ide_cdrom_dops = { ide_cdrom_dev_ioctl, /* dev_ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN - | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET - | CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */ - 0 /* n_minors */ + | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS + | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD + | CDC_DVD_R| CDC_DVD_RAM | CDC_GENERIC_PACKET, /* capability */ + 0, /* n_minors */ + ide_cdrom_packet }; static int ide_cdrom_register (ide_drive_t *drive, int nslots) @@ -2843,13 +2311,32 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) struct cdrom_device_info *devinfo = &info->devinfo; int minor = (drive->select.b.unit)<<PARTN_BITS; - devinfo->dev = MKDEV (HWIF(drive)->major, minor); + devinfo->dev = MKDEV (HWIF(drive)->major, minor | CD_PART_MASK); devinfo->ops = &ide_cdrom_dops; devinfo->mask = 0; *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed; *(int *)&devinfo->capacity = nslots; devinfo->handle = (void *) drive; strcpy(devinfo->name, drive->name); + + /* set capability mask to match the probe. */ + if (!CDROM_CONFIG_FLAGS (drive)->cd_r) + devinfo->mask |= CDC_CD_R; + if (!CDROM_CONFIG_FLAGS (drive)->cd_rw) + devinfo->mask |= CDC_CD_RW; + if (!CDROM_CONFIG_FLAGS (drive)->dvd) + devinfo->mask |= CDC_DVD; + if (!CDROM_CONFIG_FLAGS (drive)->dvd_r) + devinfo->mask |= CDC_DVD_R; + if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram) + devinfo->mask |= CDC_DVD_RAM; + if (!CDROM_CONFIG_FLAGS (drive)->is_changer) + devinfo->mask |= CDC_SELECT_DISC; + if (!CDROM_CONFIG_FLAGS (drive)->audio_play) + devinfo->mask |= CDC_PLAY_AUDIO; + if (!CDROM_CONFIG_FLAGS (drive)->close_tray) + devinfo->mask |= CDC_CLOSE_TRAY; + return register_cdrom (devinfo); } @@ -2857,8 +2344,11 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) static int ide_cdrom_probe_capabilities (ide_drive_t *drive) { - int stat, nslots = 0, attempts = 3; - struct { + struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; + int stat, nslots = 1, attempts = 3; + struct cdrom_generic_command cgc; + struct { char pad[8]; struct atapi_capabilities_page cap; } buf; @@ -2866,11 +2356,19 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) if (CDROM_CONFIG_FLAGS (drive)->nec260) return nslots; + init_cdrom_command(&cgc, &buf, sizeof(buf)); + /* we have to cheat a little here. the packet will eventually + * be queued with ide_cdrom_packet(), which extracts the + * drive from cdi->handle. Since this device hasn't been + * registered with the Uniform layer yet, it can't do this. + * Same goes cdi->ops. + */ + cdi->handle = (ide_drive_t *) drive; + cdi->ops = &ide_cdrom_dops; do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ if (attempts-- <= 0) return 0; - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, - (char *)&buf, sizeof (buf), NULL); + stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); } while (stat); if (buf.cap.lock == 0) @@ -2888,10 +2386,14 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) if (buf.cap.dvd_ram_write) CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; if (buf.cap.dvd_r_write) - CDROM_CONFIG_FLAGS (drive)->dvd_rw = 1; + CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1; + if (buf.cap.audio_play) + CDROM_CONFIG_FLAGS (drive)->audio_play = 1; + if (buf.cap.mechtype == 0) + CDROM_CONFIG_FLAGS (drive)->close_tray = 0; #if ! STANDARD_ATAPI - if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { + if (cdi->sanyo_slot > 0) { CDROM_CONFIG_FLAGS (drive)->is_changer = 1; nslots = 3; } @@ -2928,10 +2430,10 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed, (CDROM_CONFIG_FLAGS (drive)->dvd) ? "DVD-ROM" : "CD-ROM"); - if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_rw) + if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram) printk (" DVD%s%s", - (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-RAM" : "", - (CDROM_CONFIG_FLAGS (drive)->dvd_rw)? "/RW" : ""); + (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", + (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : ""); if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) printk (" CD%s%s", @@ -2971,71 +2473,24 @@ static void ide_cdrom_add_settings(ide_drive_t *drive) ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); } -#ifdef CONFIG_IDECD_SLOTS -static void ide_cdrom_slot_check (ide_drive_t *drive, int nslots) -{ - tracktype tracks; - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *devinfo = &info->devinfo; - int slot_count = 0, drive_stat = 0, tmp; - - for (slot_count=0;slot_count<nslots;slot_count++) { - (void) ide_cdrom_select_disc(devinfo, slot_count); - printk(" CD Slot %d ", slot_count+1); - - drive_stat = ide_cdrom_drive_status(devinfo, slot_count); - if (drive_stat<0) { - continue; - } else switch(drive_stat) { - case CDS_DISC_OK: - /* use routine in Uniform CD-ROM driver */ - cdrom_count_tracks(devinfo, &tracks); - tmp = tracks.audio + tracks.data + - tracks.cdi + tracks.xa; - printk(": Disc has %d track%s: ", tmp, - (tmp == 1)? "" : "s"); - printk("%d=data %d=audio %d=Cd-I %d=XA\n", - tracks.data, tracks.audio, - tracks.cdi, tracks.xa); - break; - case CDS_NO_DISC: - printk("Empty slot.\n"); - break; - case CDS_TRAY_OPEN: - printk("CD-ROM tray open.\n"); - break; - case CDS_DRIVE_NOT_READY: - printk("CD-ROM drive not ready.\n"); - break; - case CDS_NO_INFO: - printk("No Information available.\n"); - break; - default: - printk("This Should not happen!\n"); - break; - } - } - (void) ide_cdrom_select_disc(devinfo, 0); -} -#endif /* CONFIG_IDECD_SLOTS */ static int ide_cdrom_setup (ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; + int minor = drive->select.b.unit << PARTN_BITS; int nslots; - kdev_t dev = MKDEV (HWIF (drive)->major, - drive->select.b.unit << PARTN_BITS); + kdev_t dev = MKDEV(HWIF(drive)->major, minor); set_device_ro (dev, 1); - blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] = - CD_FRAMESIZE; + blksize_size[HWIF(drive)->major][minor] = CD_FRAMESIZE; drive->special.all = 0; drive->ready_stat = 0; - CDROM_STATE_FLAGS (drive)->media_changed = 0; + CDROM_STATE_FLAGS (drive)->media_changed = 1; CDROM_STATE_FLAGS (drive)->toc_valid = 0; CDROM_STATE_FLAGS (drive)->door_locked = 0; @@ -3057,9 +2512,11 @@ int ide_cdrom_setup (ide_drive_t *drive) CDROM_CONFIG_FLAGS (drive)->test_write = 0; CDROM_CONFIG_FLAGS (drive)->dvd = 0; CDROM_CONFIG_FLAGS (drive)->dvd_r = 0; - CDROM_CONFIG_FLAGS (drive)->dvd_rw = 0; + CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0; CDROM_CONFIG_FLAGS (drive)->no_eject = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0; + CDROM_CONFIG_FLAGS (drive)->audio_play = 0; + CDROM_CONFIG_FLAGS (drive)->close_tray = 1; /* limit transfer size per interrupt. */ CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0; @@ -3073,7 +2530,7 @@ int ide_cdrom_setup (ide_drive_t *drive) #if ! STANDARD_ATAPI /* by default Sanyo 3 CD changer support is turned off and ATAPI Rev 2.2+ standard support for CD changers is used */ - CDROM_STATE_FLAGS (drive)->sanyo_slot = 0; + cdi->sanyo_slot = 0; CDROM_CONFIG_FLAGS (drive)->nec260 = 0; CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0; @@ -3125,7 +2582,7 @@ int ide_cdrom_setup (ide_drive_t *drive) (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) || (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) { /* uses CD in slot 0 when value is set to 3 */ - CDROM_STATE_FLAGS (drive)->sanyo_slot = 3; + cdi->sanyo_slot = 3; } @@ -3146,11 +2603,6 @@ int ide_cdrom_setup (ide_drive_t *drive) return 1; } ide_cdrom_add_settings(drive); -#ifdef CONFIG_IDECD_SLOTS - if (CDROM_CONFIG_FLAGS (drive)->is_changer) { - ide_cdrom_slot_check(drive, nslots); - } -#endif /* CONFIG_IDECD_SLOTS */ return 0; } @@ -3193,7 +2645,6 @@ int ide_cdrom_check_media_change (ide_drive_t *drive) (drive->select.b.unit)<<PARTN_BITS)); } - static int ide_cdrom_cleanup(ide_drive_t *drive) { @@ -3278,11 +2729,12 @@ int ide_cdrom_init (void) MOD_INC_USE_COUNT; while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { /* skip drives that we were told to ignore */ - if (ignore != NULL) + if (ignore != NULL) { if (strstr(ignore, drive->name)) { printk("ide-cd: ignoring drive %s\n", drive->name); continue; } + } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk ("%s: Can't allocate a cdrom structure\n", drive->name); @@ -3309,11 +2761,3 @@ int ide_cdrom_init (void) MOD_DEC_USE_COUNT; return 0; } - - -/*==========================================================================*/ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index 553013b9d..ae1a252ed 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -1,9 +1,9 @@ #ifndef _IDE_CD_H #define _IDE_CD_H /* - * linux/drivers/block/ide_modes.h + * linux/drivers/block/ide_cd.h * - * Copyright (C) 1996 Erik Andersen + * Copyright (C) 1996, 1997, 1998 Erik Andersen * Copyright (C) 1998, 1999 Jens Axboe */ @@ -55,94 +55,37 @@ #define REQUEST_SENSE_COMMAND 4316 #define RESET_DRIVE_COMMAND 4317 -/* - * For controlling drive spindown time. - */ -#define CDROMGETSPINDOWN 0x531d -#define CDROMSETSPINDOWN 0x531e - - -/* Some ATAPI command opcodes (just like SCSI). - (Some other cdrom-specific codes are in cdrom.h.) */ -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define INQUIRY 0x12 -#define START_STOP 0x1b -#define ALLOW_MEDIUM_REMOVAL 0x1e -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define SEEK 0x2b -#define READ_HEADER 0x44 -#define STOP_PLAY_SCAN 0x4e -#define MODE_SELECT_10 0x55 -#define MODE_SENSE_10 0x5a -#define LOAD_UNLOAD 0xa6 -#define READ_12 0xa8 -#define READ_CD_MSF 0xb9 -#define SCAN 0xba -#define SET_CD_SPEED 0xbb -#define PLAY_CD 0xbc -#define MECHANISM_STATUS 0xbd -#define READ_CD 0xbe - -/* DVD Opcodes */ -#define DVD_GET_PERFORMANCE 0xac - - -/* Page codes for mode sense/set */ - -#define PAGE_READERR 0x01 -#define PAGE_CDROM 0x0d -#define PAGE_AUDIO 0x0e -#define PAGE_CAPABILITIES 0x2a -#define PAGE_ALL 0x3f - - -/* ATAPI sense keys (from table 140 of ATAPI 2.6) */ - -#define NO_SENSE 0x00 -#define RECOVERED_ERROR 0x01 -#define NOT_READY 0x02 -#define MEDIUM_ERROR 0x03 -#define HARDWARE_ERROR 0x04 -#define ILLEGAL_REQUEST 0x05 -#define UNIT_ATTENTION 0x06 -#define DATA_PROTECT 0x07 -#define ABORTED_COMMAND 0x0b -#define MISCOMPARE 0x0e - -/* We want some additional flags for CDROM drives. - To save space in the ide_drive_t struct, use some fields which - doesn't make sense for CDROMs -- `bios_cyl' and `bios_head'. */ /* Configuration flags. These describe the capabilities of the drive. They generally do not change after initialization, unless we learn more about the drive from stuff failing. */ struct ide_cd_config_flags { - __u8 drq_interrupt : 1; /* Device sends an interrupt when ready - for a packet command. */ - __u8 no_doorlock : 1; /* Drive cannot lock the door. */ - __u8 no_eject : 1; /* Drive cannot eject the disc. */ - __u8 nec260 : 1; /* Drive is a pre-1.2 NEC 260 drive. */ - __u8 playmsf_as_bcd : 1; /* PLAYMSF command takes BCD args. */ - __u8 tocaddr_as_bcd : 1; /* TOC addresses are in BCD. */ - __u8 toctracks_as_bcd : 1; /* TOC track numbers are in BCD. */ - __u8 subchan_as_bcd : 1; /* Subchannel info is in BCD. */ - __u8 is_changer : 1; /* Drive is a changer. */ - __u8 cd_r : 1; /* Drive can write to CD-R media . */ - __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */ - __u8 dvd : 1; /* Drive is a DVD-ROM */ - __u8 dvd_r : 1; /* Drive can write DVD-RAM */ - __u8 dvd_rw : 1; /* Drive can write DVD-R/W */ - __u8 test_write : 1; /* Drive can fake writes */ - __u8 supp_disc_present: 1; /* Changer can report exact contents - of slots. */ - __u8 limit_nframes : 1; /* Drive does not provide data in - multiples of SECTOR_SIZE when more - than one interrupt is needed. */ - __u8 seeking : 1; /* Seeking in progress */ - __u8 reserved : 6; - byte max_speed; /* Max speed of the drive */ + __u8 drq_interrupt : 1; /* Device sends an interrupt when ready + for a packet command. */ + __u8 no_doorlock : 1; /* Drive cannot lock the door. */ + __u8 no_eject : 1; /* Drive cannot eject the disc. */ + __u8 nec260 : 1; /* Drive is a pre-1.2 NEC 260 drive. */ + __u8 playmsf_as_bcd : 1; /* PLAYMSF command takes BCD args. */ + __u8 tocaddr_as_bcd : 1; /* TOC addresses are in BCD. */ + __u8 toctracks_as_bcd : 1; /* TOC track numbers are in BCD. */ + __u8 subchan_as_bcd : 1; /* Subchannel info is in BCD. */ + __u8 is_changer : 1; /* Drive is a changer. */ + __u8 cd_r : 1; /* Drive can write to CD-R media . */ + __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */ + __u8 dvd : 1; /* Drive is a DVD-ROM */ + __u8 dvd_r : 1; /* Drive can write DVD-R */ + __u8 dvd_ram : 1; /* Drive can write DVD-RAM */ + __u8 test_write : 1; /* Drive can fake writes */ + __u8 supp_disc_present : 1; /* Changer can report exact contents + of slots. */ + __u8 limit_nframes : 1; /* Drive does not provide data in + multiples of SECTOR_SIZE when more + than one interrupt is needed. */ + __u8 seeking : 1; /* Seeking in progress */ + __u8 audio_play : 1; /* can do audio related commands */ + __u8 close_tray : 1; /* can close the tray */ + __u8 reserved : 4; + byte max_speed; /* Max speed of the drive */ }; #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) @@ -153,8 +96,7 @@ struct ide_cd_state_flags { __u8 media_changed : 1; /* Driver has noticed a media change. */ __u8 toc_valid : 1; /* Saved TOC information is current. */ __u8 door_locked : 1; /* We think that the drive door is locked. */ - __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ - __u8 reserved : 3; + __u8 reserved : 5; byte current_speed; /* Current speed of the drive */ }; #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) @@ -276,15 +218,10 @@ struct atapi_cdrom_subchnl { }; -typedef enum { - mechtype_caddy = 0, - mechtype_tray = 1, - mechtype_popup = 2, - mechtype_individual_changer = 4, - mechtype_cartridge_changer = 5 -} mechtype_t; - +/* This should probably go into cdrom.h along with the other + * generic stuff now in the Mt. Fuji spec. + */ struct atapi_capabilities_page { #if defined(__BIG_ENDIAN_BITFIELD) __u8 parameters_saveable : 1; @@ -518,9 +455,11 @@ struct atapi_mechstat_header { #if defined(__BIG_ENDIAN_BITFIELD) __u8 mech_state : 3; - __u8 reserved1 : 5; + __u8 door_open : 1; + __u8 reserved1 : 4; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved1 : 5; + __u8 reserved1 : 4; + __u8 door_open : 1; __u8 mech_state : 3; #else #error "Please fix <asm/byteorder.h>" @@ -604,11 +543,85 @@ struct cdrom_info { #define ARY_LEN(a) ((sizeof(a) / sizeof(a[0]))) +/* This stuff should be in cdrom.h, since it is now generic... */ + +/* ATAPI sense keys (from table 140 of ATAPI 2.6) */ +#define NO_SENSE 0x00 +#define RECOVERED_ERROR 0x01 +#define NOT_READY 0x02 +#define MEDIUM_ERROR 0x03 +#define HARDWARE_ERROR 0x04 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define DATA_PROTECT 0x07 +#define ABORTED_COMMAND 0x0b +#define MISCOMPARE 0x0e + + + +/* This stuff should be in cdrom.h, since it is now generic... */ #if VERBOSE_IDE_CD_ERRORS -/* From Table 124 of the ATAPI 1.2 spec. - Unchanged in Table 140 of the ATAPI 2.6 draft standard. */ + /* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +const struct { + unsigned short packet_command; + const char * const text; +} packet_command_texts[] = { + { GPCMD_TEST_UNIT_READY, "Test Unit Ready" }, + { GPCMD_REQUEST_SENSE, "Request Sense" }, + { GPCMD_FORMAT_UNIT, "Format Unit" }, + { GPCMD_INQUIRY, "Inquiry" }, + { GPCMD_START_STOP_UNIT, "Start/Stop Unit" }, + { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, + { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" }, + { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" }, + { GPCMD_READ_10, "Read 10" }, + { GPCMD_WRITE_10, "Write 10" }, + { GPCMD_SEEK, "Seek" }, + { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" }, + { GPCMD_VERIFY_10, "Verify 10" }, + { GPCMD_FLUSH_CACHE, "Flush Cache" }, + { GPCMD_READ_SUBCHANNEL, "Read Subchannel" }, + { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" }, + { GPCMD_READ_HEADER, "Read Header" }, + { GPCMD_PLAY_AUDIO_10, "Play Audio 10" }, + { GPCMD_GET_CONFIGURATION, "Get Configuration" }, + { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" }, + { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" }, + { GPCMD_GET_EVENT_STATUS_NOTIFICATION, "Get Event Status Notification" }, + { GPCMD_PAUSE_RESUME, "Pause/Resume" }, + { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" }, + { GPCMD_READ_DISC_INFO, "Read Disc Info" }, + { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" }, + { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" }, + { GPCMD_SEND_OPC, "Send OPC" }, + { GPCMD_MODE_SELECT_10, "Mode Select 10" }, + { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" }, + { GPCMD_MODE_SENSE_10, "Mode Sense 10" }, + { GPCMD_CLOSE_TRACK, "Close Track" }, + { GPCMD_BLANK, "Blank" }, + { GPCMD_SEND_EVENT, "Send Event" }, + { GPCMD_SEND_KEY, "Send Key" }, + { GPCMD_REPORT_KEY, "Report Key" }, + { GPCMD_LOAD_UNLOAD, "Load/Unload" }, + { GPCMD_SET_READ_AHEAD, "Set Read-ahead" }, + { GPCMD_READ_12, "Read 12" }, + { GPCMD_GET_PERFORMANCE, "Get Performance" }, + { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" }, + { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" }, + { GPCMD_SET_STREAMING, "Set Streaming" }, + { GPCMD_READ_CD_MSF, "Read CD MSF" }, + { GPCMD_SCAN, "Scan" }, + { GPCMD_SET_SPEED, "Set Speed" }, + { GPCMD_PLAY_CD, "Play CD" }, + { GPCMD_MECHANISM_STATUS, "Mechanism Status" }, + { GPCMD_READ_CD, "Read CD" }, +}; + + +/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ const char * const sense_key_texts[16] = { "No sense data", "Recovered error", @@ -628,162 +641,108 @@ const char * const sense_key_texts[16] = { "(reserved)", }; - -/* From Table 37 of the ATAPI 2.6 draft standard. */ +/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ const struct { - unsigned short packet_command; - const char * const text; -} packet_command_texts[] = { - { TEST_UNIT_READY, "Test Unit Ready" }, - { REQUEST_SENSE, "Request Sense" }, - { INQUIRY, "Inquiry" }, - { START_STOP, "Start Stop Unit" }, - { ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, - { READ_CAPACITY, "Read CD-ROM Capacity" }, - { READ_10, "Read(10)" }, - { SEEK, "Seek" }, - { SCMD_READ_TOC, "Read TOC" }, - { SCMD_READ_SUBCHANNEL, "Read Sub-Channel" }, - { READ_HEADER, "Read Header" }, - { STOP_PLAY_SCAN, "Stop Play/Scan" }, - { SCMD_PLAYAUDIO10, "Play Audio" }, - { SCMD_PLAYAUDIO_MSF, "Play Audio MSF" }, - { SCMD_PAUSE_RESUME, "Pause/Resume" }, - { MODE_SELECT_10, "Mode Select" }, - { MODE_SENSE_10, "Mode Sense" }, - { LOAD_UNLOAD, "Load/Unload CD" }, - { READ_12, "Read(12)" }, - { READ_CD_MSF, "Read CD MSF" }, - { SCAN, "Scan" }, - { SET_CD_SPEED, "Set CD Speed" }, - { PLAY_CD, "Play CD" }, - { MECHANISM_STATUS, "Mechanism Status" }, - { READ_CD, "Read CD" }, - { DVD_GET_PERFORMANCE, "Get Performance" }, -}; - - -/* From Table 125 of the ATAPI 1.2 spec., - with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */ - -const struct { - unsigned short asc_ascq; + unsigned long asc_ascq; const char * const text; } sense_data_texts[] = { - { 0x0000, "No additional sense information" }, - - { 0x0011, "Audio play operation in progress" }, - { 0x0012, "Audio play operation paused" }, - { 0x0013, "Audio play operation successfully completed" }, - { 0x0014, "Audio play operation stopped due to error" }, - { 0x0015, "No current audio status to return" }, - - { 0x0100, "Mechanical positioning or changer error" }, - - { 0x0200, "No seek complete" }, - - { 0x0400, "Logical unit not ready - cause not reportable" }, - { 0x0401, - "Logical unit not ready - in progress (sic) of becoming ready" }, - { 0x0402, "Logical unit not ready - initializing command required" }, - { 0x0403, "Logical unit not ready - manual intervention required" }, - - { 0x0501, "Media load - eject failed" }, - - { 0x0600, "No reference position found" }, - - { 0x0900, "Track following error" }, - { 0x0901, "Tracking servo failure" }, - { 0x0902, "Focus servo failure" }, - { 0x0903, "Spindle servo failure" }, - - { 0x1100, "Unrecovered read error" }, - { 0x1106, "CIRC unrecovered error" }, - - { 0x1500, "Random positioning error" }, - { 0x1501, "Mechanical positioning or changer error" }, - { 0x1502, "Positioning error detected by read of medium" }, - - { 0x1700, "Recovered data with no error correction applied" }, - { 0x1701, "Recovered data with retries" }, - { 0x1702, "Recovered data with positive head offset" }, - { 0x1703, "Recovered data with negative head offset" }, - { 0x1704, "Recovered data with retries and/or CIRC applied" }, - { 0x1705, "Recovered data using previous sector ID" }, - - { 0x1800, "Recovered data with error correction applied" }, - { 0x1801, "Recovered data with error correction and retries applied" }, - { 0x1802, "Recovered data - the data was auto-reallocated" }, - { 0x1803, "Recovered data with CIRC" }, - { 0x1804, "Recovered data with L-EC" }, - /* Following two not in 2.6. */ - { 0x1805, "Recovered data - recommend reassignment" }, - { 0x1806, "Recovered data - recommend rewrite" }, - - { 0x1a00, "Parameter list length error" }, - - { 0x2000, "Invalid command operation code" }, - - { 0x2100, "Logical block address out of range" }, - - { 0x2400, "Invalid field in command packet" }, - - { 0x2600, "Invalid field in parameter list" }, - { 0x2601, "Parameter not supported" }, - { 0x2602, "Parameter value invalid" }, - /* Following code not in 2.6. */ - { 0x2603, "Threshold parameters not supported" }, - - { 0x2800, "Not ready to ready transition, medium may have changed" }, - - { 0x2900, "Power on, reset or bus device reset occurred" }, - - { 0x2a00, "Parameters changed" }, - { 0x2a01, "Mode parameters changed" }, - - { 0x3000, "Incompatible medium installed" }, - { 0x3001, "Cannot read medium - unknown format" }, - { 0x3002, "Cannot read medium - incompatible format" }, - - /* Following code not in 2.6. */ - { 0x3700, "Rounded parameter" }, - - { 0x3900, "Saving parameters not supported" }, - - { 0x3a00, "Medium not present" }, - - { 0x3f00, "ATAPI CD-ROM drive operating conditions have changed" }, - { 0x3f01, "Microcode has been changed" }, - /* Following two not in 2.6. */ - { 0x3f02, "Changed operating definition" }, - { 0x3f03, "Inquiry data has changed" }, - - { 0x4000, "Diagnostic failure on component (ASCQ)" }, - - { 0x4400, "Internal ATAPI CD-ROM drive failure" }, - - { 0x4e00, "Overlapped commands attempted" }, - - { 0x5300, "Media load or eject failed" }, - { 0x5302, "Medium removal prevented" }, - - { 0x5700, "Unable to recover table of contents" }, - - { 0x5a00, "Operator request or state change input (unspecified)" }, - { 0x5a01, "Operator medium removal request" }, - - /* Following two not in 2.6. */ - { 0x5b00, "Threshold condition met" }, - { 0x5c00, "Status change" }, - - { 0x6300, "End of user area encountered on this track" }, - - { 0x6400, "Illegal mode for this track or incompatible medium" }, - - /* Following error is misspelled in ATAPI 2.6 */ - { 0xb900, "Play operation oborted [sic]" }, - - { 0xbf00, "Loss of streaming" }, + { 0x000000, "No additional sense information" }, + { 0x000011, "Play operation in progress" }, + { 0x000012, "Play operation paused" }, + { 0x000013, "Play operation successfully completed" }, + { 0x000014, "Play operation stopped due to error" }, + { 0x000015, "No current audio status to return" }, + { 0x011700, "Recovered data with no error correction applied" }, + { 0x011701, "Recovered data with retries" }, + { 0x011702, "Recovered data with positive head offset" }, + { 0x011703, "Recovered data with negative head offset" }, + { 0x011704, "Recovered data with retries and/or CIRC applied" }, + { 0x011705, "Recovered data using previous sector ID" }, + { 0x011800, "Recovered data with error correction applied" }, + { 0x011801, "Recovered data with error correction and retries applied"}, + { 0x011802, "Recovered data - the data was auto-reallocated" }, + { 0x011803, "Recovered data with CIRC" }, + { 0x011804, "Recovered data with L-EC" }, + { 0x015d00, + "Failure prediction threshold exceeded - Predicted logical unit failure" }, + { 0x015d01, + "Failure prediction threshold exceeded - Predicted media failure" }, + { 0x015dff, "Failure prediction threshold exceeded - False" }, + { 0x020400, "Logical unit not ready - cause not reportable" }, + /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ + { 0x020401, + "Logical unit not ready - in progress [sic] of becoming ready" }, + { 0x020402, "Logical unit not ready - initializing command required" }, + { 0x020403, "Logical unit not ready - manual intervention required" }, + { 0x020404, "In process of becoming ready - writing" }, + { 0x020600, "No reference position found (media may be upside down)" }, + { 0x023000, "Incompatible medium installed" }, + { 0x023a00, "Medium not present" }, + { 0x025300, "Media load or eject failed" }, + { 0x025700, "Unable to recover table of contents" }, + { 0x031100, "Unrecovered read error" }, + { 0x031106, "CIRC unrecovered error" }, + { 0x033101, "Format command failed" }, + { 0x040200, "No seek complete" }, + { 0x040300, "Write fault" }, + { 0x040900, "Track following error" }, + { 0x040901, "Tracking servo failure" }, + { 0x040902, "Focus servo failure" }, + { 0x040903, "Spindle servo failure" }, + { 0x041500, "Random positioning error" }, + { 0x041501, "Mechanical positioning or changer error" }, + { 0x041502, "Positioning error detected by read of medium" }, + { 0x043c00, "Mechanical positioning or changer error" }, + { 0x044000, "Diagnostic failure on component (ASCQ)" }, + { 0x044400, "Internal CD/DVD logical unit failure" }, + { 0x04b600, "Media load mechanism failed" }, + { 0x051a00, "Parameter list length error" }, + { 0x052000, "Invalid command operation code" }, + { 0x052c00, "Command sequence error" }, + { 0x052100, "Logical block address out of range" }, + { 0x052400, "Invalid field in command packet" }, + { 0x052600, "Invalid field in parameter list" }, + { 0x052601, "Parameter not supported" }, + { 0x052602, "Parameter value invalid" }, + { 0x052700, "Write protected media" }, + { 0x053001, "Cannot read medium - unknown format" }, + { 0x053002, "Cannot read medium - incompatible format" }, + { 0x053900, "Saving parameters not supported" }, + { 0x054e00, "Overlapped commands attempted" }, + { 0x055302, "Medium removal prevented" }, + { 0x055500, "System resource failure" }, + { 0x056300, "End of user area encountered on this track" }, + { 0x056400, "Illegal mode for this track or incompatible medium" }, + { 0x056f00, + "Copy protection key exchange failure - Authentication failure" }, + { 0x056f01, "Copy protection key exchange failure - Key not present" }, + { 0x056f02, + "Copy protection key exchange failure - Key not established" }, + { 0x05bf00, "Loss of streaming" }, + { 0x062800, "Not ready to ready transition, medium may have changed" }, + { 0x062900, "Power on, reset or hardware reset occurred" }, + { 0x062a00, "Parameters changed" }, + { 0x062a01, "Mode parameters changed" }, + { 0x062e00, "Insufficient time for operation" }, + { 0x063f00, "Logical unit operating conditions have changed" }, + { 0x063f01, "Microcode has been changed" }, + { 0x065a00, "Operator request or state change input (unspecified)" }, + { 0x065a01, "Operator medium removal request" }, + { 0x0bb900, "Play operation aborted" }, + + /* Here we use 0xff for the key (not a valid key) to signify + * that these can have _any_ key value associated with them... */ + { 0xff0401, "Logical unit is in process of becoming ready" }, + { 0xff0400, "Logical unit not ready, cause not reportable" }, + { 0xff0402, "Logical unit not ready, initializing command required" }, + { 0xff0403, "Logical unit not ready, manual intervention required" }, + { 0xff0500, "Logical unit does not respond to selection" }, + { 0xff0800, "Logical unit communication failure" }, + { 0xff0802, "Logical unit communication parity error" }, + { 0xff0801, "Logical unit communication time-out" }, + { 0xff2500, "Logical unit not supported" }, + { 0xff4c00, "Logical unit failed self-configuration" }, + { 0xff3e00, "Logical unit has not self-configured yet" }, }; #endif diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 0cda4398c..cd631c621 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 * * Copyright (c) 1999 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -357,12 +357,11 @@ static int config_drive_for_dma (ide_drive_t *drive) /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); -#ifdef CONFIG_IDEDMA_ULTRA_66 + /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */ - if ((id->field_valid & 4) && (id->word93 & 0x2000)) + if ((id->field_valid & 4) && (hwif->udma_four) && (id->word93 & 0x2000)) if ((id->dma_ultra & (id->dma_ultra >> 11) & 3)) return hwif->dmaproc(ide_dma_on, drive); -#endif /* CONFIG_IDEDMA_ULTRA_66 */ /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) @@ -443,6 +442,12 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_bad_drive: case ide_dma_good_drive: return check_drive_lists(drive, (func == ide_dma_good_drive)); + case ide_dma_lostirq: + case ide_dma_timeout: + /* + * printk("ide_dmaproc: chipset supported func only: %d\n", func); + */ + return 1; default: printk("ide_dmaproc: unsupported func: %d\n", func); return 1; @@ -465,7 +470,7 @@ int ide_release_dma (ide_hwif_t *hwif) } /* - * This can be called for a dynamically installed interface. Don't initfunc it + * This can be called for a dynamically installed interface. Don't __init it */ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports) @@ -510,7 +515,7 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p /* * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: */ -__initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)) +unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) { unsigned long dma_base = 0; struct pci_dev *dev = hwif->pci_dev; @@ -518,7 +523,7 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c if (hwif->mate && hwif->mate->dma_base) { dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); } else { - dma_base = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + dma_base = dev->resource[4].start; if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) { printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base); dma_base = 0; @@ -532,10 +537,6 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c switch(dev->device) { case PCI_DEVICE_ID_CMD_643: - /* - * Lets attempt to use the same Ali tricks - * to fix CMD643..... - */ #ifdef CONFIG_BLK_DEV_ALI15X3 case PCI_DEVICE_ID_AL_M5219: case PCI_DEVICE_ID_AL_M5229: @@ -550,9 +551,19 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c } break; default: - if (inb(dma_base+2) & 0x80) { - printk("%s: simplex device: DMA disabled\n", name); - dma_base = 0; + /* + * If the device claims "simplex" DMA, + * this means only one of the two interfaces + * can be trusted with DMA at any point in time. + * So we should enable DMA only on one of the + * two interfaces. + */ + if ((inb(dma_base+2) & 0x80)) { /* simplex device? */ + if ((!hwif->drives[0].present && !hwif->drives[1].present) || + (hwif->mate && hwif->mate->dma_base)) { + printk("%s: simplex device: DMA disabled\n", name); + dma_base = 0; + } } } } diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index 49ccb66ce..66b71b3a2 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.8 Dec 7, 1997 + * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 * - * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> */ /* @@ -26,9 +26,12 @@ * Issue START command only if TEST UNIT READY fails. * Add work-around for IOMEGA ZIP revision 21.D. * Remove idefloppy_get_capabilities(). + * Ver 0.9 Jul 4 99 Fix a bug which might have caused the number of + * bytes requested on each interrupt to be zero. + * Thanks to <shanos@es.co.nz> for pointing this out. */ -#define IDEFLOPPY_VERSION "0.8" +#define IDEFLOPPY_VERSION "0.9" #include <linux/config.h> #include <linux/module.h> @@ -997,7 +1000,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) pc->retries++; pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; - bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ + bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024); #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { @@ -1521,9 +1524,19 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) floppy->pc = floppy->pc_stack; if (gcw.drq_type == 1) set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags); - if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 && - ((strcmp(drive->id->fw_rev, "21.D") == 0) || - (strcmp(drive->id->fw_rev, "23.D") == 0))) { + /* + * We used to check revisions here. At this point however + * I'm giving up. Just assume they are all broken, its easier. + * + * The actual reason for the workarounds was likely + * a driver bug after all rather than a firmware bug, + * and the workaround below used to hide it. It should + * be fixed as of version 1.9, but to be on the safe side + * we'll leave the limitation below for the 2.2.x tree. + */ + + if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) + { for (i = 0; i < 1 << PARTN_BITS; i++) max_sectors[major][minor + i] = 64; } diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index 019aec4fb..3ba39f600 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-pci.c Version 1.03 May 1, 1999 + * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 * * Copyright (c) 1998-1999 Andre Hedrick * @@ -52,6 +52,7 @@ #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF}) #define DEVID_HPT34X ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) +#define DEVID_HPT366 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366}) #define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) @@ -106,11 +107,14 @@ extern void ide_init_rz1000(ide_hwif_t *); #endif #ifdef CONFIG_BLK_DEV_VIA82C586 +extern unsigned int pci_init_via82c568(struct pci_dev *, const char *); extern void ide_init_via82c586(ide_hwif_t *); extern void ide_dmacapable_via82c586(ide_hwif_t *, unsigned long dmabase); +#define PCI_VIA82C586 &pci_init_via82c568 #define INIT_VIA82C586 &ide_init_via82c586 #define DMA_VIA82C586 &ide_dmacapable_via82c586 #else +#define PCI_VIA82C586 NULL #define INIT_VIA82C586 NULL #define DMA_VIA82C586 NULL #endif @@ -126,9 +130,12 @@ extern void ide_init_ali15x3(ide_hwif_t *); #endif #ifdef CONFIG_BLK_DEV_CY82C693 +extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *); extern void ide_init_cy82c693(ide_hwif_t *); +#define PCI_CY82C693 &pci_init_cy82c693 #define INIT_CY82C693 &ide_init_cy82c693 #else +#define PCI_CY82C693 NULL #define INIT_CY82C693 NULL #endif @@ -166,6 +173,26 @@ extern void ide_init_hpt34x(ide_hwif_t *); #define INIT_HPT34X NULL #endif +#ifdef CONFIG_BLK_DEV_HPT366 +extern unsigned int pci_init_hpt366(struct pci_dev *, const char *); +extern void ide_init_hpt366(ide_hwif_t *); +#define PCI_HPT366 &pci_init_hpt366 +#define INIT_HPT366 &ide_init_hpt366 +#else +#define PCI_HPT366 NULL +#define INIT_HPT366 IDE_IGNORE +#endif + +#ifdef CONFIG_BLK_DEV_SIS5513 +extern unsigned int pci_init_sis5513(struct pci_dev *, const char *); +extern void ide_init_sis5513(ide_hwif_t *); +#define PCI_SIS5513 &pci_init_sis5513 +#define INIT_SIS5513 &ide_init_sis5513 +#else +#define PCI_SIS5513 NULL +#define INIT_SIS5513 NULL +#endif + #define INIT_SAMURAI NULL #define INIT_CX5530 NULL @@ -183,71 +210,76 @@ typedef struct ide_pci_device_s { void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase); ide_pci_enablebit_t enablebits[2]; byte bootable; + byte sixtysix; unsigned int extra; } ide_pci_device_t; static ide_pci_device_t ide_pci_chipsets[] __initdata = { - {DEVID_PIIXa, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_VP_IDE, "VP_IDE", NULL, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, - {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, - {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, - {DEVID_RZ1000, "RZ1000", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_RZ1001, "RZ1001", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_SAMURAI, "SAMURAI", NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD640, "CMD640", NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87410, "NS87410", NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, - {DEVID_SIS5513, "SIS5513", NULL, NULL, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, - {DEVID_CMD643, "CMD643", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD646, "CMD646", NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_HT6565, "HT6565", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621, "OPTI621", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621X,"OPTI621X", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_TRM290, "TRM290", NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87415, "NS87415", NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, - {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, - {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0 }, - {DEVID_CY82C693,"CY82C693", NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; + {DEVID_PIIXa, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_VP_IDE, "VP_IDE", PCI_VIA82C586, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, 0 }, + {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 0, 16 }, + {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 1, 48 }, + {DEVID_RZ1000, "RZ1000", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_RZ1001, "RZ1001", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_SAMURAI, "SAMURAI", NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_CMD640, "CMD640", NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_NS87410, "NS87410", NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 }, + {DEVID_SIS5513, "SIS5513", PCI_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 1, 0 }, + {DEVID_CMD643, "CMD643", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_CMD646, "CMD646", NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0, 0 }, + {DEVID_HT6565, "HT6565", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_OPTI621, "OPTI621", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_OPTI621X,"OPTI621X", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_TRM290, "TRM290", NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_NS87415, "NS87415", NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, 0 }, + {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0, 0 }, + {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, 16 }, + {DEVID_HPT366, "HPT366", PCI_HPT366, INIT_HPT366, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 1, 256 }, + {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0, 0 }, + {DEVID_CY82C693,"CY82C693", PCI_CY82C693, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }}; + +static byte hpt363_shared_irq = 0; /* * This allows offboard ide-pci cards the enable a BIOS, verify interrupt * settings of split-mirror pci-config space, place chipset into init-mode, * and/or preserve an interrupt if the card is not native ide support. */ -__initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const char *name)) +static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name) { switch(dev->device) { case PCI_DEVICE_ID_TTI_HPT343: { - int i; unsigned short pcicmd = 0; - unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; pci_write_config_byte(dev, 0x80, 0x00); - dev->base_address[0] = (hpt34xIoBase + 0x20); - dev->base_address[1] = (hpt34xIoBase + 0x34); - dev->base_address[2] = (hpt34xIoBase + 0x28); - dev->base_address[3] = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); if (!(pcicmd & PCI_COMMAND_MEMORY)) { + int i; + unsigned long hpt34xIoBase = dev->resource[4].start; + + dev->resource[0].start = (hpt34xIoBase + 0x20); + dev->resource[1].start = (hpt34xIoBase + 0x34); + dev->resource[2].start = (hpt34xIoBase + 0x28); + dev->resource[3].start = (hpt34xIoBase + 0x3c); + for(i=0; i<4; i++) + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } else { pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } } + case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: case PCI_DEVICE_ID_ARTOP_ATP850UF: @@ -262,7 +294,7 @@ __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const * Match a PCI IDE port against an entry in ide_hwifs[], * based on io_base port if possible. */ -__initfunc(static ide_hwif_t *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)) +static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name) { int h; ide_hwif_t *hwif; @@ -324,7 +356,7 @@ __initfunc(static ide_hwif_t *ide_match_hwif (unsigned long io_base, byte bootab return NULL; } -__initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)) +static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name) { byte reg, progif = 0; @@ -346,11 +378,15 @@ __initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *n /* * Setup base registers for IDE command/control spaces for each interface: */ - for (reg = 0; reg < 4; reg++) - if (!dev->base_address[reg]) { + for (reg = 0; reg < 4; reg++) { + struct resource *res = dev->resource + reg; + if (!(res->flags & PCI_BASE_ADDRESS_SPACE_IO)) + continue; + if (!res->start) { printk("%s: Missing I/O address #%d\n", name, reg); return 1; } + } return 0; } @@ -364,7 +400,7 @@ __initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *n * we "know" about, this information is in the ide_pci_device_t struct; * for all other chipsets, we just assume both interfaces are enabled. */ -__initfunc(static void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)) +static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d) { unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0; unsigned short pcicmd = 0, tried_config = 0; @@ -446,9 +482,19 @@ check_if_enabled: ide_pci_enablebit_t *e = &(d->enablebits[port]); if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) continue; /* port not enabled */ + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port)) + return; if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { - ctl = dev->base_address[(2*port)+1] & PCI_BASE_ADDRESS_IO_MASK; - base = dev->base_address[2*port] & ~7; + ctl = dev->resource[(2*port)+1].start; + base = dev->resource[2*port].start; + if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || + !(base & PCI_BASE_ADDRESS_IO_MASK)) { + printk("%s: IO baseregs (BIOS) are reported as MEM, report to <andre@suse.com>.\n", d->name); +#if 0 + /* FIXME! This really should check that it really gets the IO/MEM part right! */ + continue; +#endif + } } if ((ctl && !base) || (base && !ctl)) { printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port); @@ -484,13 +530,12 @@ check_if_enabled: hwif->irq = hwif->channel ? 15 : 14; goto bypass_umc_dma; } - + if ((!d->sixtysix) && (hwif->udma_four)) + hwif->udma_four = 0; #ifdef CONFIG_BLK_DEV_IDEDMA if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) autodma = 0; - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) - hwif->udma_four = 1; if (autodma) hwif->autodma = 1; if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || @@ -499,6 +544,7 @@ check_if_enabled: #ifdef CONFIG_BLK_DEV_HPT34X IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || #endif /* CONFIG_BLK_DEV_HPT34X */ + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); @@ -534,11 +580,49 @@ bypass_umc_dma: printk("%s: neither IDE port enabled (BIOS)\n", d->name); } +static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) +{ + struct pci_dev *dev2; + ide_pci_device_t *d2; + unsigned char pin1 = 0, pin2 = 0; + + d2 = d; + if (PCI_FUNC(dev->devfn) & 1) + return; + + for (dev2=pci_devices; dev2; dev2=dev2->next) { + if ((dev2->vendor == dev->vendor) && + (dev2->device == dev->device) && + (PCI_FUNC(dev2->devfn) & 1)) + break; + } + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); + if (dev2) { + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); + hpt363_shared_irq = (pin1 != pin2) ? 1 : 0; + } + + if (hpt363_shared_irq) { + printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", + d->name, pin1, pin2); + } + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + + if (dev2 && !hpt363_shared_irq) { + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d2->name, dev2->bus->number, dev2->devfn); + ide_setup_pci_device(dev2, d2); + } +} + /* * ide_scan_pcibus() gets invoked at boot time from ide.c. * It finds all PCI IDE controllers and calls ide_setup_pci_device for them. */ -__initfunc(void ide_scan_pcibus (void)) +void __init ide_scan_pcibus (void) { struct pci_dev *dev; ide_pci_devid_t devid; @@ -558,6 +642,8 @@ __initfunc(void ide_scan_pcibus (void)) continue; /* CY82C693 is more than only a IDE controller */ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1)) continue; /* UM8886A/BF pair */ + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366)) + hpt366_device_order_fixup(dev, d); else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n", diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c index 52c658311..90fbf9cbc 100644 --- a/drivers/block/ide-pmac.c +++ b/drivers/block/ide-pmac.c @@ -57,38 +57,47 @@ struct notifier_block idepmac_sleep_notifier = { #endif /* CONFIG_PMAC_PBOOK */ /* - * N.B. this can't be an initfunc, because the media-bay task can + * N.B. this can't be an __init, because the media-bay task can * call ide_[un]register at any time. */ -void pmac_ide_init_hwif_ports ( hw_regs_t *hw, - ide_ioreg_t data_port, - ide_ioreg_t ctrl_port, - int *irq) +void pmac_ide_init_hwif_ports(hw_regs_t *hw, + ide_ioreg_t data_port, ide_ioreg_t ctrl_port, + int *irq) { - int i, r; + int i, ix; if (data_port == 0) return; + + for (ix = 0; ix < MAX_HWIFS; ++ix) + if (data_port == pmac_ide_regbase[ix]) + break; + + if (ix >= MAX_HWIFS) { + /* Probably a PCI interface... */ + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i) + hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET; + /* XXX is this right? */ + hw->io_ports[IDE_CONTROL_OFFSET] = 0; + if (irq != 0) + *irq = 0; + return; + } + /* we check only for -EINVAL meaning that we have found a matching bay but with the wrong device type */ - - r = check_media_bay_by_base(data_port, MB_CD); - if (r == -EINVAL) + i = check_media_bay_by_base(data_port, MB_CD); + if (i == -EINVAL) { + hw->io_ports[IDE_DATA_OFFSET] = 0; return; - - for ( i = 0; i < 8 ; ++i ) + } + + for (i = 0; i < 8; ++i) hw->io_ports[i] = data_port + i * 0x10; hw->io_ports[8] = data_port + 0x160; - if (irq != NULL) { - *irq = 0; - for (i = 0; i < MAX_HWIFS; ++i) { - if (data_port == pmac_ide_regbase[i]) { - *irq = pmac_ide_irq[i]; - break; - } - } - } + if (irq != NULL) + *irq = pmac_ide_irq[ix]; } void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) @@ -100,15 +109,15 @@ void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) pio = ide_get_best_pio_mode(drive, pio, 4, &d); switch (pio) { case 4: - out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x211025); + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025); break; default: - out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x2f8526); + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526); break; } } -__initfunc(void pmac_ide_probe(void)) +void __init pmac_ide_probe(void) { struct device_node *np; int i; @@ -145,14 +154,36 @@ __initfunc(void pmac_ide_probe(void)) *pp = removables; for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { + struct device_node *tp; + + /* + * If this node is not under a mac-io or dbdma node, + * leave it to the generic PCI driver. + */ + for (tp = np->parent; tp != 0; tp = tp->parent) + if (tp->type && (strcmp(tp->type, "mac-io") == 0 + || strcmp(tp->type, "dbdma") == 0)) + break; + if (tp == 0) + continue; + if (np->n_addrs == 0) { printk(KERN_WARNING "ide: no address for device %s\n", np->full_name); continue; } - base = (unsigned long) ioremap(np->addrs[0].address, 0x200); - + /* + * If this slot is taken (e.g. by ide-pci.c) try the next one. + */ + while (i < MAX_HWIFS + && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0) + ++i; + if (i >= MAX_HWIFS) + break; + + base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE; + /* XXX This is bogus. Should be fixed in the registry by checking the kind of host interrupt controller, a bit like gatwick fixes in irq.c @@ -199,8 +230,8 @@ __initfunc(void pmac_ide_probe(void)) #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC -__initfunc(static void -pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif)) +static void __init +pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif) { hwif->dma_base = (unsigned long) ioremap(np->addrs[1].address, 0x200); diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 76dc905dd..62008341e 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -20,7 +20,7 @@ * Version 1.04 fixed buggy treatments of known flash memory cards * * Version 1.05 fix for (hwif->chipset == ide_pdc4030) - * added ide6/7 + * added ide6/7/8/9 * allowed for secondary flash card to be detectable * with new flag : drive->ata_flash : 1; */ @@ -352,56 +352,6 @@ static inline byte probe_for_drive (ide_drive_t *drive) } /* - * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc - * controller that is BIOS compatible with ST-506, and thus showing up in our - * BIOS table, but not register compatible, and therefore not present in CMOS. - * - * Furthermore, we will assume that our ST-506 drives <if any> are the primary - * drives in the system -- the ones reflected as drive 1 or 2. The first - * drive is stored in the high nibble of CMOS byte 0x12, the second in the low - * nibble. This will be either a 4 bit drive type or 0xf indicating use byte - * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value - * means we have an AT controller hard disk for that drive. - * - * Of course, there is no guarantee that either drive is actually on the - * "primary" IDE interface, but we don't bother trying to sort that out here. - * If a drive is not actually on the primary interface, then these parameters - * will be ignored. This results in the user having to supply the logical - * drive geometry as a boot parameter for each drive not on the primary i/f. - * - * The only "perfect" way to handle this would be to modify the setup.[cS] code - * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info - * for us during initialization. I have the necessary docs -- any takers? -ml - */ -static void probe_cmos_for_drives (ide_hwif_t *hwif) -{ -#ifdef __i386__ - extern struct drive_info_struct drive_info; - byte cmos_disks, *BIOS = (byte *) &drive_info; - int unit; - -#ifdef CONFIG_BLK_DEV_PDC4030 - if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) - return; -#endif /* CONFIG_BLK_DEV_PDC4030 */ - outb_p(0x12,0x70); /* specify CMOS address 0x12 */ - cmos_disks = inb_p(0x71); /* read the data from 0x12 */ - /* Extract drive geometry from CMOS+BIOS if not already setup */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) { - drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS; - drive->head = drive->bios_head = *(BIOS+2); - drive->sect = drive->bios_sect = *(BIOS+14); - drive->ctl = *(BIOS+8); - drive->present = 1; - } - BIOS += 16; - } -#endif -} - -/* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. */ @@ -418,8 +368,11 @@ static void probe_hwif (ide_hwif_t *hwif) if (hwif->noprobe) return; - if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) + if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) { + extern void probe_cmos_for_drives(ide_hwif_t *hwif); + probe_cmos_for_drives (hwif); + } /* * Calculate the region that this interface occupies, @@ -763,6 +716,12 @@ static int hwif_init (ide_hwif_t *hwif) #if MAX_HWIFS > 7 case IDE7_MAJOR: rfn = &do_ide7_request; break; #endif +#if MAX_HWIFS > 8 + case IDE8_MAJOR: rfn = &do_ide8_request; break; +#endif +#if MAX_HWIFS > 9 + case IDE9_MAJOR: rfn = &do_ide9_request; break; +#endif default: printk("%s: request_fn NOT DEFINED\n", hwif->name); return (hwif->present = 0); diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index 623ac9268..8afe1568f 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -243,6 +243,7 @@ static int proc_ide_write_config } #endif /* CONFIG_BLK_DEV_IDEPCI */ } else { /* not pci */ +#ifndef CONFIG_Q40 switch (digits) { case 2: outb(val, reg); break; @@ -251,6 +252,7 @@ static int proc_ide_write_config case 8: outl(val, reg); break; } +#endif /* CONFIG_Q40 */ } } } diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index ed278655e..6e8313733 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -3583,8 +3583,9 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) /* * These two ide-pci host adapters appear to need this disabled. */ - if ((hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || - (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) { + if (HWIF(drive)->pci_dev != NULL && ( + (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || + (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343))) { drive->dsc_overlap = 0; } else #endif /* CONFIG_BLK_DEV_IDEPCI */ diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 9a09e7ec3..74b3f71c6 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.19 January 29, 1999 + * linux/drivers/block/ide.c Version 6.20 July 10, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -39,7 +39,7 @@ * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: * * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg) - * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2") + * Delman Lee (delman@ieee.org) ("Mr. atdisk2") * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) * * This was a rewrite of just about everything from hd.c, though some original @@ -93,19 +93,28 @@ * Version 6.17 fix for newest EZ-Drive problem * Version 6.18 default unpartitioned-disk translation now "BIOS LBA" * Version 6.19 Re-design for a UNIFORM driver for all platforms, - * model based on suggestions from Russell King and - * Geert Uytterhoeven + * model based on suggestions from Russell King and + * Geert Uytterhoeven * Promise DC4030VL now supported. + * add support for ide6/ide7 * delay_50ms() changed to ide_delay_50ms() and exported. + * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection. + * Added hdx=flash to allow for second flash disk + * detection w/o the hang loop. + * Added support for ide8/ide9 + * Added idex=ata66 for the quirky chipsets that are + * ATA-66 compliant, but have yet to determine a method + * of verification of the 80c cable presence. + * Specifically Promise's PDC20262 chipset. * - * Some additional driver compile-time options are in ide.h + * Some additional driver compile-time options are in ./include/linux/ide.h * * To do, in likely order of completion: * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f */ -#define REVISION "Revision: 6.19" -#define VERSION "Id: ide.c 6.19 1999/01/29" +#define REVISION "Revision: 6.20" +#define VERSION "Id: ide.c 6.20 1999/07/10" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -144,7 +153,11 @@ extern byte fifoconfig; /* defined in via82c586.c used by ide_setup()*/ #endif -static const byte ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR }; +static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, + IDE2_MAJOR, IDE3_MAJOR, + IDE4_MAJOR, IDE5_MAJOR, + IDE6_MAJOR, IDE7_MAJOR, + IDE8_MAJOR, IDE9_MAJOR }; static int idebus_parameter; /* holds the "idebus=" parameter */ static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ @@ -421,8 +434,8 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) { ++bytecount; -#ifdef CONFIG_ATARI - if (MACH_IS_ATARI) { +#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) + if (MACH_IS_ATARI || MACH_IS_Q40) { /* Atari has a byte-swapped IDE interface */ insw_swapw(IDE_DATA_REG, buffer, bytecount / 2); return; @@ -436,8 +449,8 @@ void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) { ++bytecount; -#ifdef CONFIG_ATARI - if (MACH_IS_ATARI) { +#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) + if (MACH_IS_ATARI || MACH_IS_Q40) { /* Atari has a byte-swapped IDE interface */ outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2); return; @@ -1187,7 +1200,9 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags return; } hwif = HWIF(drive); - if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) /* set nIEN for previous hwif */ + if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && + hwif->io_ports[IDE_CONTROL_OFFSET]) + /* set nIEN for previous hwif */ OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]); hwgroup->hwif = hwif; hwgroup->drive = drive; @@ -1308,6 +1323,20 @@ void do_ide7_request (void) } #endif /* MAX_HWIFS > 7 */ +#if MAX_HWIFS > 8 +void do_ide8_request (void) +{ + unlock_do_hwgroup_request (ide_hwifs[8].hwgroup); +} +#endif /* MAX_HWIFS > 8 */ + +#if MAX_HWIFS > 9 +void do_ide9_request (void) +{ + unlock_do_hwgroup_request (ide_hwifs[9].hwgroup); +} +#endif /* MAX_HWIFS > 9 */ + static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq) { unsigned long flags; @@ -1347,6 +1376,7 @@ void ide_timer_expiry (unsigned long data) handler(drive); } else if (drive_is_ready(drive)) { printk("%s: lost interrupt\n", drive->name); + (void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive); spin_unlock_irqrestore(&hwgroup->spinlock, flags); handler(drive); } else { @@ -1357,6 +1387,7 @@ void ide_timer_expiry (unsigned long data) * need something here for HPT34X.......AMH * irq timeout: status=0x58 { DriveReady SeekComplete DataRequest } */ + (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive); } spin_unlock_irqrestore(&hwgroup->spinlock, flags); ide_error(drive, "irq timeout", GET_STAT()); @@ -1957,7 +1988,7 @@ int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp) } for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; - if ((!hwif->present && !initializing) || + if ((!hwif->present && !hwif->mate && !initializing) || (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing)) goto found; } @@ -2248,7 +2279,8 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed) * this point (lost interrupt). */ SELECT_DRIVE(HWIF(drive), drive); - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(speed, IDE_NSECTOR_REG); OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); @@ -2524,7 +2556,7 @@ char *ide_xfer_verbose (byte xfer_rate) { * stridx() returns the offset of c within s, * or -1 if c is '\0' or not found within s. */ -__initfunc(static int stridx (const char *s, char c)) +static int __init stridx (const char *s, char c) { char *i = strchr(s, c); return (i && c) ? i - s : -1; @@ -2542,7 +2574,7 @@ __initfunc(static int stridx (const char *s, char c)) * and base16 is allowed when prefixed with "0x". * 4. otherwise, zero is returned. */ -__initfunc(static int match_parm (char *s, const char *keywords[], int vals[], int max_vals)) +static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals) { static const char *decimal = "0123456789"; static const char *hex = "0123456789abcdef"; @@ -2641,6 +2673,10 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i * "idex=four" : four drives on idex and ide(x^1) share same ports * "idex=reset" : reset interface before first use * "idex=dma" : enable DMA by default on both drives if possible + * "idex=ata66" : informs the interface that it has an 80c cable + * for chipsets that are ATA-66 capable, but + * the ablity to bit test for detection is + * currently unknown. * * "splitfifo=betweenChan" * : FIFO Configuration of VIA 82c586(<nothing>,"A"or"B"). @@ -2668,8 +2704,9 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i * "ide0=ali14xx" : probe/support ali14xx chipsets (ALI M1439, M1443, M1445) * "ide0=umc8672" : probe/support umc8672 chipsets * "idex=dc4030" : probe/support Promise DC4030VL interface + * "ide=doubler" : probe/support IDE doublers on Amiga */ -__initfunc(void ide_setup (char *s)) +void __init ide_setup (char *s) { int i, vals[3]; ide_hwif_t *hwif; @@ -2828,9 +2865,12 @@ __initfunc(void ide_setup (char *s)) if (s[3] >= '0' && s[3] <= max_hwif) { /* * Be VERY CAREFUL changing this: note hardcoded indexes below + * -8,-9,-10 : are reserved for future idex calls to ease the hardcoding. */ - const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "four", - "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL}; + const char *ide_words[] = { + "noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", + "minus8", "minus9", "minus10", + "four", "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL }; hw = s[3] - '0'; hwif = &ide_hwifs[hw]; i = match_parm(&s[4], ide_words, vals, 3); @@ -2838,19 +2878,19 @@ __initfunc(void ide_setup (char *s)) /* * Cryptic check to ensure chipset not already set for hwif: */ - if (i > 0 || i <= -7) { /* is parameter a chipset name? */ + if (i > 0 || i <= -11) { /* is parameter a chipset name? */ if (hwif->chipset != ide_unknown) goto bad_option; /* chipset already specified */ - if (i <= -7 && i != -14 && hw != 0) + if (i <= -11 && i != -18 && hw != 0) goto bad_hwif; /* chipset drivers are for "ide0=" only */ - if (i <= -7 && i != -14 && ide_hwifs[hw+1].chipset != ide_unknown) + if (i <= -11 && i != -18 && ide_hwifs[hw+1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ printk("\n"); } switch (i) { #ifdef CONFIG_BLK_DEV_PDC4030 - case -14: /* "dc4030" */ + case -18: /* "dc4030" */ { extern void init_pdc4030(void); init_pdc4030(); @@ -2858,7 +2898,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_PDC4030 */ #ifdef CONFIG_BLK_DEV_ALI14XX - case -13: /* "ali14xx" */ + case -17: /* "ali14xx" */ { extern void init_ali14xx (void); init_ali14xx(); @@ -2866,7 +2906,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_ALI14XX */ #ifdef CONFIG_BLK_DEV_UMC8672 - case -12: /* "umc8672" */ + case -16: /* "umc8672" */ { extern void init_umc8672 (void); init_umc8672(); @@ -2874,7 +2914,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_UMC8672 */ #ifdef CONFIG_BLK_DEV_DTC2278 - case -11: /* "dtc2278" */ + case -15: /* "dtc2278" */ { extern void init_dtc2278 (void); init_dtc2278(); @@ -2882,7 +2922,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_DTC2278 */ #ifdef CONFIG_BLK_DEV_CMD640 - case -10: /* "cmd640_vlb" */ + case -14: /* "cmd640_vlb" */ { extern int cmd640_vlb; /* flag for cmd640.c */ cmd640_vlb = 1; @@ -2890,7 +2930,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_CMD640 */ #ifdef CONFIG_BLK_DEV_HT6560B - case -9: /* "ht6560b" */ + case -13: /* "ht6560b" */ { extern void init_ht6560b (void); init_ht6560b(); @@ -2898,7 +2938,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_HT6560B */ #if CONFIG_BLK_DEV_QD6580 - case -8: /* "qd6580" */ + case -12: /* "qd6580" */ { extern void init_qd6580 (void); init_qd6580(); @@ -2906,7 +2946,7 @@ __initfunc(void ide_setup (char *s)) } #endif /* CONFIG_BLK_DEV_QD6580 */ #ifdef CONFIG_BLK_DEV_4DRIVES - case -7: /* "four" drives on one set of ports */ + case -11: /* "four" drives on one set of ports */ { ide_hwif_t *mate = &ide_hwifs[hw^1]; mate->drives[0].select.all ^= 0x20; @@ -2917,6 +2957,18 @@ __initfunc(void ide_setup (char *s)) goto do_serialize; } #endif /* CONFIG_BLK_DEV_4DRIVES */ + case -10: /* minus10 */ + case -9: /* minus9 */ + case -8: /* minus8 */ + goto bad_option; + case -7: /* ata66 */ +#ifdef CONFIG_BLK_DEV_IDEPCI + hwif->udma_four = 1; + goto done; +#else /* !CONFIG_BLK_DEV_IDEPCI */ + hwif->udma_four = 0; + goto bad_hwif; +#endif /* CONFIG_BLK_DEV_IDEPCI */ case -6: /* dma */ hwif->autodma = 1; goto done; @@ -3080,7 +3132,7 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) /* * probe_for_hwifs() finds/initializes "known" IDE interfaces */ -__initfunc(static void probe_for_hwifs (void)) +static void __init probe_for_hwifs (void) { #ifdef CONFIG_PCI if (pci_present()) @@ -3154,7 +3206,7 @@ __initfunc(static void probe_for_hwifs (void)) #endif /* CONFIG_BLK_DEV_BUDDHA */ } -__initfunc(void ide_init_builtin_drivers (void)) +void __init ide_init_builtin_drivers (void) { /* * Probe for special PCI and other "known" interface chipsets @@ -3425,6 +3477,12 @@ EXPORT_SYMBOL(do_ide6_request); #if MAX_HWIFS > 7 EXPORT_SYMBOL(do_ide7_request); #endif /* MAX_HWIFS > 7 */ +#if MAX_HWIFS > 8 +EXPORT_SYMBOL(do_ide8_request); +#endif /* MAX_HWIFS > 8 */ +#if MAX_HWIFS > 9 +EXPORT_SYMBOL(do_ide9_request); +#endif /* MAX_HWIFS > 9 */ /* * Driver module @@ -3469,7 +3527,7 @@ EXPORT_SYMBOL(ide_setup_ports); /* * This is gets invoked once during initialization, to set *everything* up */ -__initfunc(int ide_init (void)) +int __init ide_init (void) { static char banner_printed = 0; @@ -3491,7 +3549,7 @@ __initfunc(int ide_init (void)) char *options = NULL; MODULE_PARM(options,"s"); -__initfunc(static void parse_options (char *line)) +static void __init parse_options (char *line) { char *next = line; diff --git a/drivers/block/ide.h b/drivers/block/ide.h deleted file mode 100644 index 2ca3266ec..000000000 --- a/drivers/block/ide.h +++ /dev/null @@ -1,773 +0,0 @@ -#ifndef _IDE_H -#define _IDE_H -/* - * linux/drivers/block/ide.h - * - * Copyright (C) 1994-1998 Linus Torvalds & authors - */ - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/hdreg.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <asm/ide.h> - -/* - * This is the multiple IDE interface driver, as evolved from hd.c. - * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15). - * There can be up to two drives per interface, as per the ATA-2 spec. - * - * Primary i/f: ide0: major=3; (hda) minor=0; (hdb) minor=64 - * Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64 - * Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64 - * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64 - */ - -/****************************************************************************** - * IDE driver configuration options (play with these as desired): - * - * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary - */ -#undef REALLY_FAST_IO /* define if ide ports are perfect */ -#define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */ - -#ifndef SUPPORT_SLOW_DATA_PORTS /* 1 to support slow data ports */ -#define SUPPORT_SLOW_DATA_PORTS 1 /* 0 to reduce kernel size */ -#endif -#ifndef SUPPORT_VLB_SYNC /* 1 to support weird 32-bit chips */ -#define SUPPORT_VLB_SYNC 1 /* 0 to reduce kernel size */ -#endif -#ifndef DISK_RECOVERY_TIME /* off=0; on=access_delay_time */ -#define DISK_RECOVERY_TIME 0 /* for hardware that needs it */ -#endif -#ifndef OK_TO_RESET_CONTROLLER /* 1 needed for good error recovery */ -#define OK_TO_RESET_CONTROLLER 1 /* 0 for use with AH2372A/B interface */ -#endif -#ifndef FAKE_FDISK_FOR_EZDRIVE /* 1 to help linux fdisk with EZDRIVE */ -#define FAKE_FDISK_FOR_EZDRIVE 1 /* 0 to reduce kernel size */ -#endif -#ifndef FANCY_STATUS_DUMPS /* 1 for human-readable drive errors */ -#define FANCY_STATUS_DUMPS 1 /* 0 to reduce kernel size */ -#endif - -#ifdef CONFIG_BLK_DEV_CMD640 -#if 0 /* change to 1 when debugging cmd640 problems */ -void cmd640_dump_regs (void); -#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */ -#endif -#endif /* CONFIG_BLK_DEV_CMD640 */ - -/* - * IDE_DRIVE_CMD is used to implement many features of the hdparm utility - */ -#define IDE_DRIVE_CMD 99 /* (magic) undef to reduce kernel size*/ - -/* - * "No user-serviceable parts" beyond this point :) - *****************************************************************************/ - -typedef unsigned char byte; /* used everywhere */ - -/* - * Probably not wise to fiddle with these - */ -#define ERROR_MAX 8 /* Max read/write errors per sector */ -#define ERROR_RESET 3 /* Reset controller every 4th retry */ -#define ERROR_RECAL 1 /* Recalibrate every 2nd retry */ - -/* - * Ensure that various configuration flags have compatible settings - */ -#ifdef REALLY_SLOW_IO -#undef REALLY_FAST_IO -#endif - -#define HWIF(drive) ((ide_hwif_t *)((drive)->hwif)) -#define HWGROUP(drive) ((ide_hwgroup_t *)(HWIF(drive)->hwgroup)) - -/* - * Definitions for accessing IDE controller registers - */ -#define IDE_NR_PORTS (10) - -#define IDE_DATA_OFFSET (0) -#define IDE_ERROR_OFFSET (1) -#define IDE_NSECTOR_OFFSET (2) -#define IDE_SECTOR_OFFSET (3) -#define IDE_LCYL_OFFSET (4) -#define IDE_HCYL_OFFSET (5) -#define IDE_SELECT_OFFSET (6) -#define IDE_STATUS_OFFSET (7) -#define IDE_CONTROL_OFFSET (8) -#define IDE_IRQ_OFFSET (9) - -#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET -#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET - -#define IDE_DATA_REG (HWIF(drive)->io_ports[IDE_DATA_OFFSET]) -#define IDE_ERROR_REG (HWIF(drive)->io_ports[IDE_ERROR_OFFSET]) -#define IDE_NSECTOR_REG (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET]) -#define IDE_SECTOR_REG (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET]) -#define IDE_LCYL_REG (HWIF(drive)->io_ports[IDE_LCYL_OFFSET]) -#define IDE_HCYL_REG (HWIF(drive)->io_ports[IDE_HCYL_OFFSET]) -#define IDE_SELECT_REG (HWIF(drive)->io_ports[IDE_SELECT_OFFSET]) -#define IDE_STATUS_REG (HWIF(drive)->io_ports[IDE_STATUS_OFFSET]) -#define IDE_CONTROL_REG (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]) -#define IDE_IRQ_REG (HWIF(drive)->io_ports[IDE_IRQ_OFFSET]) - -#define IDE_FEATURE_REG IDE_ERROR_REG -#define IDE_COMMAND_REG IDE_STATUS_REG -#define IDE_ALTSTATUS_REG IDE_CONTROL_REG -#define IDE_IREASON_REG IDE_NSECTOR_REG -#define IDE_BCOUNTL_REG IDE_LCYL_REG -#define IDE_BCOUNTH_REG IDE_HCYL_REG - -#ifdef REALLY_FAST_IO -#define OUT_BYTE(b,p) outb((b),(p)) -#define IN_BYTE(p) (byte)inb(p) -#else -#define OUT_BYTE(b,p) outb_p((b),(p)) -#define IN_BYTE(p) (byte)inb_p(p) -#endif /* REALLY_FAST_IO */ - -#define GET_ERR() IN_BYTE(IDE_ERROR_REG) -#define GET_STAT() IN_BYTE(IDE_STATUS_REG) -#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good)) -#define BAD_R_STAT (BUSY_STAT | ERR_STAT) -#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) -#define BAD_STAT (BAD_R_STAT | DRQ_STAT) -#define DRIVE_READY (READY_STAT | SEEK_STAT) -#define DATA_READY (DRQ_STAT) - -/* - * Some more useful definitions - */ -#define IDE_MAJOR_NAME "ide" /* the same for all i/f; see also genhd.c */ -#define MAJOR_NAME IDE_MAJOR_NAME -#define PARTN_BITS 6 /* number of minor dev bits for partitions */ -#define PARTN_MASK ((1<<PARTN_BITS)-1) /* a useful bit mask */ -#define MAX_DRIVES 2 /* per interface; 2 assumed by lots of code */ -#define SECTOR_WORDS (512 / 4) /* number of 32bit words per sector */ -#define IDE_LARGE_SEEK(b1,b2,t) (((b1) > (b2) + (t)) || ((b2) > (b1) + (t))) -#define IDE_MIN(a,b) ((a)<(b) ? (a):(b)) -#define IDE_MAX(a,b) ((a)>(b) ? (a):(b)) - -/* - * Timeouts for various operations: - */ -#define WAIT_DRQ (5*HZ/100) /* 50msec - spec allows up to 20ms */ -#ifdef CONFIG_APM -#define WAIT_READY (5*HZ) /* 5sec - some laptops are very slow */ -#else -#define WAIT_READY (3*HZ/100) /* 30msec - should be instantaneous */ -#endif /* CONFIG_APM */ -#define WAIT_PIDENTIFY (10*HZ) /* 10sec - should be less than 3ms (?) - if all ATAPI CD is closed at boot */ -#define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ -#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ -#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ - -#define SELECT_DRIVE(hwif,drive) \ -{ \ - if (hwif->selectproc) \ - hwif->selectproc(drive); \ - OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \ -} - -/* - * Now for the data we need to maintain per-drive: ide_drive_t - */ - -#define ide_scsi 0x21 -#define ide_disk 0x20 -#define ide_optical 0x7 -#define ide_cdrom 0x5 -#define ide_tape 0x1 -#define ide_floppy 0x0 - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned set_geometry : 1; /* respecify drive geometry */ - unsigned recalibrate : 1; /* seek to cyl 0 */ - unsigned set_multmode : 1; /* set multmode count */ - unsigned set_tune : 1; /* tune interface for drive */ - unsigned reserved : 4; /* unused */ - } b; - } special_t; - -typedef struct ide_drive_s { - struct request *queue; /* request queue */ - struct ide_drive_s *next; /* circular list of hwgroup drives */ - unsigned long sleep; /* sleep until this time */ - unsigned long service_start; /* time we started last request */ - unsigned long service_time; /* service time of last request */ - special_t special; /* special action flags */ - byte keep_settings; /* restore settings after drive reset */ - byte using_dma; /* disk is using dma for read/write */ - byte waiting_for_dma; /* dma currently in progress */ - byte unmask; /* flag: okay to unmask other irqs */ - byte slow; /* flag: slow data port */ - byte bswap; /* flag: byte swap data */ - byte dsc_overlap; /* flag: DSC overlap */ - byte nice1; /* flag: give potential excess bandwidth */ - unsigned present : 1; /* drive is physically present */ - unsigned noprobe : 1; /* from: hdx=noprobe */ - unsigned busy : 1; /* currently doing revalidate_disk() */ - unsigned removable : 1; /* 1 if need to do check_media_change */ - unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ - unsigned no_unmask : 1; /* disallow setting unmask bit */ - unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ - unsigned nobios : 1; /* flag: do not probe bios for drive */ - unsigned revalidate : 1; /* request revalidation */ - unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ - unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ - unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ - unsigned doorlocking : 1; /* flag: for removable only: door lock/unlock works */ - unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ -#if FAKE_FDISK_FOR_EZDRIVE - unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */ -#endif /* FAKE_FDISK_FOR_EZDRIVE */ - byte media; /* disk, cdrom, tape, floppy, ... */ - select_t select; /* basic drive/head select reg value */ - byte ctl; /* "normal" value for IDE_CONTROL_REG */ - byte ready_stat; /* min status value for drive ready */ - byte mult_count; /* current multiple sector setting */ - byte mult_req; /* requested multiple sector setting */ - byte tune_req; /* requested drive tuning setting */ - byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ - byte bad_wstat; /* used for ignoring WRERR_STAT */ - byte nowerr; /* used for ignoring WRERR_STAT */ - byte sect0; /* offset of first sector for DM6:DDO */ - byte usage; /* current "open()" count for drive */ - byte head; /* "real" number of heads */ - byte sect; /* "real" sectors per track */ - /* - * HACK: enforce alignment for sake of IDE CDROM driver on - * architectures with strict alignment rules. - */ - byte bios_head __attribute__ ((aligned (8))); /* BIOS/fdisk/LILO number of heads */ - byte bios_sect __attribute__ ((aligned (8))); /* BIOS/fdisk/LILO sectors per track */ - unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */ - unsigned short cyl; /* "real" number of cyls */ - unsigned int drive_data; /* for use by tuneproc/selectproc as needed */ - void *hwif; /* actually (ide_hwif_t *) */ - struct wait_queue *wqueue; /* used to wait for drive in open() */ - struct hd_driveid *id; /* drive model identification info */ - struct hd_struct *part; /* drive partition table */ - char name[4]; /* drive name, such as "hda" */ - void *driver; /* (ide_driver_t *) */ - void *driver_data; /* extra driver data */ - struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ - void *settings; /* /proc/ide/ drive settings */ - char driver_req[10]; /* requests specific driver */ - } ide_drive_t; - -/* - * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * Returns 0 if all went well. - * Returns 1 if DMA read/write could not be started, in which case the caller - * should either try again later, or revert to PIO for the current request. - */ -typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end, - ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly, - ide_dma_test_irq - } ide_dma_action_t; - -typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); - - -/* - * An ide_tuneproc_t() is used to set the speed of an IDE interface - * to a particular PIO mode. The "byte" parameter is used - * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255 - * indicates that the interface driver should "auto-tune" the PIO mode - * according to the drive capabilities in drive->id; - * - * Not all interface types support tuning, and not all of those - * support all possible PIO settings. They may silently ignore - * or round values as they see fit. - */ -typedef void (ide_tuneproc_t)(ide_drive_t *, byte); - -/* - * This is used to provide support for strange interfaces - */ -typedef void (ide_selectproc_t) (ide_drive_t *); - -/* - * hwif_chipset_t is used to keep track of the specific hardware - * chipset used by each IDE interface, if known. - */ -typedef enum { ide_unknown, ide_generic, ide_pci, - ide_cmd640, ide_dtc2278, ide_ali14xx, - ide_qd6580, ide_umc8672, ide_ht6560b, - ide_pdc4030, ide_rz1000, ide_trm290, - ide_cmd646, ide_4drives - } hwif_chipset_t; - -typedef struct ide_pci_devid_s { - unsigned short vid; - unsigned short did; -} ide_pci_devid_t; - -#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0}) -#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did) - -typedef struct hwif_s { - struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ - void *hwgroup; /* actually (ide_hwgroup_t *) */ - ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ - ide_drive_t drives[MAX_DRIVES]; /* drive info */ - struct gendisk *gd; /* gendisk structure */ - ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ - ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ - ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ - unsigned long *dmatable; /* dma physical region descriptor table */ - struct hwif_s *mate; /* other hwif from same PCI chip */ - unsigned long dma_base; /* base addr for dma ports */ - unsigned dma_extra; /* extra addr for dma ports */ - unsigned long config_data; /* for use by chipset-specific code */ - unsigned long select_data; /* for use by chipset-specific code */ - struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ - int irq; /* our irq number */ - byte major; /* our major number */ - char name[6]; /* name of interface, eg. "ide0" */ - byte index; /* 0 for ide0; 1 for ide1; ... */ - hwif_chipset_t chipset; /* sub-module for tuning.. */ - unsigned noprobe : 1; /* don't probe for this interface */ - unsigned present : 1; /* this interface exists */ - unsigned serialized : 1; /* serialized operation with mate hwif */ - unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ - unsigned reset : 1; /* reset after probe */ - unsigned autodma : 1; /* automatically try to enable DMA at boot */ - byte channel; /* for dual-port chips: 0=primary, 1=secondary */ - struct pci_dev *pci_dev; /* for pci chipsets */ - ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */ -#if (DISK_RECOVERY_TIME > 0) - unsigned long last_time; /* time when previous rq was done */ -#endif - } ide_hwif_t; - -/* - * internal ide interrupt handler type - */ -typedef void (ide_handler_t)(ide_drive_t *); - -typedef struct hwgroup_s { - spinlock_t spinlock; /* protects "busy" and "handler" */ - ide_handler_t *handler;/* irq handler, if active */ - int busy; /* BOOL: protects all fields below */ - ide_drive_t *drive; /* current drive */ - ide_hwif_t *hwif; /* ptr to current hwif in linked-list */ - struct request *rq; /* current request */ - struct timer_list timer; /* failsafe timer */ - struct request wrq; /* local copy of current write rq */ - unsigned long poll_timeout; /* timeout value during long polls */ - } ide_hwgroup_t; - -/* - * configurable drive settings - */ - -#define TYPE_INT 0 -#define TYPE_INTA 1 -#define TYPE_BYTE 2 -#define TYPE_SHORT 3 - -#define SETTING_READ (1 << 0) -#define SETTING_WRITE (1 << 1) -#define SETTING_RW (SETTING_READ | SETTING_WRITE) - -typedef int (ide_procset_t)(ide_drive_t *, int); -typedef struct ide_settings_s { - char *name; - int rw; - int read_ioctl; - int write_ioctl; - int data_type; - int min; - int max; - int mul_factor; - int div_factor; - void *data; - ide_procset_t *set; - int auto_remove; - struct ide_settings_s *next; -} ide_settings_t; - -void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); -void ide_remove_setting(ide_drive_t *drive, char *name); -ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name); -int ide_read_setting(ide_drive_t *t, ide_settings_t *setting); -int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val); -void ide_add_generic_settings(ide_drive_t *drive); - -/* - * /proc/ide interface - */ -typedef struct { - const char *name; - mode_t mode; - read_proc_t *read_proc; - write_proc_t *write_proc; -} ide_proc_entry_t; - -#ifdef CONFIG_PROC_FS -void proc_ide_create(void); -void proc_ide_destroy(void); -void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data); -void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p); -read_proc_t proc_ide_read_capacity; -read_proc_t proc_ide_read_geometry; - -/* - * Standard exit stuff: - */ -#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \ -{ \ - len -= off; \ - if (len < count) { \ - *eof = 1; \ - if (len <= 0) \ - return 0; \ - } else \ - len = count; \ - *start = page + off; \ - return len; \ -} -#else -#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0; -#endif - -/* - * Subdrivers support. - */ -#define IDE_SUBDRIVER_VERSION 1 - -typedef int (ide_cleanup_proc)(ide_drive_t *); -typedef void (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long); -typedef void (ide_end_request_proc)(byte, ide_hwgroup_t *); -typedef int (ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long); -typedef int (ide_open_proc)(struct inode *, struct file *, ide_drive_t *); -typedef void (ide_release_proc)(struct inode *, struct file *, ide_drive_t *); -typedef int (ide_check_media_change_proc)(ide_drive_t *); -typedef void (ide_pre_reset_proc)(ide_drive_t *); -typedef unsigned long (ide_capacity_proc)(ide_drive_t *); -typedef void (ide_special_proc)(ide_drive_t *); -typedef void (ide_setting_proc)(ide_drive_t *); - -typedef struct ide_driver_s { - const char *name; - const char *version; - byte media; - unsigned busy : 1; - unsigned supports_dma : 1; - unsigned supports_dsc_overlap : 1; - ide_cleanup_proc *cleanup; - ide_do_request_proc *do_request; - ide_end_request_proc *end_request; - ide_ioctl_proc *ioctl; - ide_open_proc *open; - ide_release_proc *release; - ide_check_media_change_proc *media_change; - ide_pre_reset_proc *pre_reset; - ide_capacity_proc *capacity; - ide_special_proc *special; - ide_proc_entry_t *proc; - } ide_driver_t; - -#define DRIVER(drive) ((ide_driver_t *)((drive)->driver)) - -/* - * IDE modules. - */ -#define IDE_CHIPSET_MODULE 0 /* not supported yet */ -#define IDE_PROBE_MODULE 1 -#define IDE_DRIVER_MODULE 2 - -typedef int (ide_module_init_proc)(void); - -typedef struct ide_module_s { - int type; - ide_module_init_proc *init; - void *info; - struct ide_module_s *next; -} ide_module_t; - -/* - * ide_hwifs[] is the master data structure used to keep track - * of just about everything in ide.c. Whenever possible, routines - * should be using pointers to a drive (ide_drive_t *) or - * pointers to a hwif (ide_hwif_t *), rather than indexing this - * structure directly (the allocation/layout may change!). - * - */ -#ifndef _IDE_C -extern ide_hwif_t ide_hwifs[]; /* master data repository */ -extern ide_module_t *ide_modules; -#endif - -/* - * We need blk.h, but we replace its end_request by our own version. - */ -#define IDE_DRIVER /* Toggle some magic bits in blk.h */ -#define LOCAL_END_REQUEST /* Don't generate end_request in blk.h */ -#include <linux/blk.h> - -void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); - -/* - * This is used for (nearly) all data transfers from/to the IDE interface - */ -void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); -void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); - -/* - * This is used for (nearly) all ATAPI data transfers from/to the IDE interface - */ -void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); -void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); - -/* - * This is used on exit from the driver, to designate the next irq handler - * and also to start the safety timer. - */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout); - -/* - * Error reporting, in human readable form (luxurious, but a memory hog). - */ -byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat); - -/* - * ide_error() takes action based on the error returned by the controller. - * The calling function must return afterwards, to restart the request. - */ -void ide_error (ide_drive_t *drive, const char *msg, byte stat); - -/* - * Issue a simple drive command - * The drive must be selected beforehand. - */ -void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler); - -/* - * ide_fixstring() cleans up and (optionally) byte-swaps a text string, - * removing leading/trailing blanks and compressing internal blanks. - * It is primarily used to tidy up the model name/number fields as - * returned by the WIN_[P]IDENTIFY commands. - */ -void ide_fixstring (byte *s, const int bytecount, const int byteswap); - -/* - * This routine busy-waits for the drive status to be not "busy". - * It then checks the status for all of the "good" bits and none - * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() -- caller should return. - * - */ -int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout); - -/* - * This routine is called from the partition-table code in genhd.c - * to "convert" a drive to a logical geometry with fewer than 1024 cyls. - * - * The second parameter, "xparm", determines exactly how the translation - * will be handled: - * 0 = convert to CHS with fewer than 1024 cyls - * using the same method as Ontrack DiskManager. - * 1 = same as "0", plus offset everything by 63 sectors. - * -1 = similar to "0", plus redirect sector 0 to sector 1. - * >1 = convert to a CHS geometry with "xparm" heads. - * - * Returns 0 if the translation was not possible, if the device was not - * an IDE disk drive, or if a geometry was "forced" on the commandline. - * Returns 1 if the geometry translation was successful. - */ -int ide_xlate_1024 (kdev_t, int, const char *); - -/* - * Start a reset operation for an IDE interface. - * The caller should return immediately after invoking this. - */ -void ide_do_reset (ide_drive_t *); - -/* - * This function is intended to be used prior to invoking ide_do_drive_cmd(). - */ -void ide_init_drive_cmd (struct request *rq); - -/* - * "action" parameter type for ide_do_drive_cmd() below. - */ -typedef enum - {ide_wait, /* insert rq at end of list, and wait for it */ - ide_next, /* insert rq immediately after current request */ - ide_preempt, /* insert rq in front of current request */ - ide_end} /* insert rq at end of list, but don't wait for it */ - ide_action_t; - -/* - * This function issues a special IDE device request - * onto the request queue. - * - * If action is ide_wait, then the rq is queued at the end of the - * request queue, and the function sleeps until it has been processed. - * This is for use when invoked from an ioctl handler. - * - * If action is ide_preempt, then the rq is queued at the head of - * the request queue, displacing the currently-being-processed - * request and this function returns immediately without waiting - * for the new rq to be completed. This is VERY DANGEROUS, and is - * intended for careful use by the ATAPI tape/cdrom driver code. - * - * If action is ide_next, then the rq is queued immediately after - * the currently-being-processed-request (if any), and the function - * returns without waiting for the new rq to be completed. As above, - * This is VERY DANGEROUS, and is intended for careful use by the - * ATAPI tape/cdrom driver code. - * - * If action is ide_end, then the rq is queued at the end of the - * request queue, and the function returns immediately without waiting - * for the new rq to be completed. This is again intended for careful - * use by the ATAPI tape/cdrom driver code. - */ -int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action); - -/* - * Clean up after success/failure of an explicit drive cmd. - * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD). - */ -void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); - -/* - * Issue ATA command and wait for completion. - */ -int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf); - -/* - * ide_system_bus_speed() returns what we think is the system VESA/PCI - * bus speed (in MHz). This is used for calculating interface PIO timings. - * The default is 40 for known PCI systems, 50 otherwise. - * The "idebus=xx" parameter can be used to override this value. - */ -int ide_system_bus_speed (void); - -/* - * ide_multwrite() transfers a block of up to mcount sectors of data - * to a drive as part of a disk multwrite operation. - */ -void ide_multwrite (ide_drive_t *drive, unsigned int mcount); - -/* - * ide_stall_queue() can be used by a drive to give excess bandwidth back - * to the hwgroup by sleeping for timeout jiffies. - */ -void ide_stall_queue (ide_drive_t *drive, unsigned long timeout); - -/* - * ide_get_queue() returns the queue which corresponds to a given device. - */ -struct request **ide_get_queue (kdev_t dev); - -/* - * CompactFlash cards and their brethern pretend to be removable hard disks, - * but they never have a slave unit, and they don't have doorlock mechanisms. - * This test catches them, and is invoked elsewhere when setting appropriate config bits. - */ -int drive_is_flashcard (ide_drive_t *drive); - -int ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags); -void ide_timer_expiry (unsigned long data); -void ide_intr (int irq, void *dev_id, struct pt_regs *regs); -void ide_geninit (struct gendisk *gd); -void do_ide0_request (void); -#if MAX_HWIFS > 1 -void do_ide1_request (void); -#endif -#if MAX_HWIFS > 2 -void do_ide2_request (void); -#endif -#if MAX_HWIFS > 3 -void do_ide3_request (void); -#endif -#if MAX_HWIFS > 4 -void do_ide4_request (void); -#endif -#if MAX_HWIFS > 5 -void do_ide5_request (void); -#endif -void ide_init_subdrivers (void); - -#ifndef _IDE_C -extern struct file_operations ide_fops[]; -#endif - -#ifdef _IDE_C -#ifdef CONFIG_BLK_DEV_IDE -int ideprobe_init (void); -#endif /* CONFIG_BLK_DEV_IDE */ -#ifdef CONFIG_BLK_DEV_IDEDISK -int idedisk_init (void); -#endif /* CONFIG_BLK_DEV_IDEDISK */ -#ifdef CONFIG_BLK_DEV_IDECD -int ide_cdrom_init (void); -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDETAPE -int idetape_init (void); -#endif /* CONFIG_BLK_DEV_IDETAPE */ -#ifdef CONFIG_BLK_DEV_IDEFLOPPY -int idefloppy_init (void); -#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ -#ifdef CONFIG_BLK_DEV_IDESCSI -int idescsi_init (void); -#endif /* CONFIG_BLK_DEV_IDESCSI */ -#endif /* _IDE_C */ - -int ide_register_module (ide_module_t *module); -void ide_unregister_module (ide_module_t *module); -ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n); -int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); -int ide_unregister_subdriver (ide_drive_t *drive); -int ide_replace_subdriver(ide_drive_t *drive, const char *driver); - -#ifdef CONFIG_BLK_DEV_IDEPCI -#define ON_BOARD 1 -#define NEVER_BOARD 0 -#ifdef CONFIG_BLK_DEV_OFFBOARD -# define OFF_BOARD ON_BOARD -#else /* CONFIG_BLK_DEV_OFFBOARD */ -# define OFF_BOARD NEVER_BOARD -#endif /* CONFIG_BLK_DEV_OFFBOARD */ - -unsigned long ide_find_free_region (unsigned short size) __init; -void ide_scan_pcibus (void) __init; -#endif -#ifdef CONFIG_BLK_DEV_IDEDMA -#define BAD_DMA_DRIVE 0 -#define GOOD_DMA_DRIVE 1 -int ide_build_dmatable (ide_drive_t *drive); -void ide_dma_intr (ide_drive_t *drive); -int check_drive_lists (ide_drive_t *drive, int good_bad); -int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive); -int ide_release_dma (ide_hwif_t *hwif); -void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init; -unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; -#endif - -#ifdef CONFIG_BLK_DEV_PDC4030 -#include "pdc4030.h" -#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030) -#else -#define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */ -#endif /* CONFIG_BLK_DEV_PDC4030 */ - -#endif /* _IDE_H */ diff --git a/drivers/block/linear.c b/drivers/block/linear.c index b6f72fd6a..3993417d0 100644 --- a/drivers/block/linear.c +++ b/drivers/block/linear.c @@ -184,7 +184,7 @@ static struct md_personality linear_personality= #ifndef MODULE -__initfunc(void linear_init (void)) +void __init linear_init (void) { register_md_personality (LINEAR, &linear_personality); } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index c4824b9b2..bc7ef4803 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -26,6 +26,14 @@ #include <linux/module.h> /* + * MAC Floppy IWM hooks + */ + +#ifdef CONFIG_MAC_FLOPPY_IWM +extern int mac_floppy_init(void); +#endif + +/* * The request-struct contains all necessary data * to load a nr of sectors into memory */ @@ -109,6 +117,11 @@ int * max_readahead[MAX_BLKDEV] = { NULL, NULL, }; */ int * max_sectors[MAX_BLKDEV] = { NULL, NULL, }; +/* + * Max number of segments per request + */ +int * max_segments[MAX_BLKDEV] = { NULL, NULL, }; + static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -116,6 +129,13 @@ static inline int get_max_sectors(kdev_t dev) return max_sectors[MAJOR(dev)][MINOR(dev)]; } +static inline int get_max_segments(kdev_t dev) +{ + if (!max_segments[MAJOR(dev)]) + return MAX_SEGMENTS; + return max_segments[MAJOR(dev)][MINOR(dev)]; +} + /* * Is called with the request spinlock aquired. * NOTE: the device-specific queue() functions @@ -286,30 +306,37 @@ static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, * with the request-lists in peace. Thus it should be called with no spinlocks * held. * - * By this point, req->cmd is always either READ/WRITE, never READA/WRITEA, + * By this point, req->cmd is always either READ/WRITE, never READA, * which is important for drive_stat_acct() above. */ void add_request(struct blk_dev_struct * dev, struct request * req) { + int major = MAJOR(req->rq_dev); + int minor = MINOR(req->rq_dev); struct request * tmp, **current_request; short disk_index; unsigned long flags; int queue_new_request = 0; - switch (MAJOR(req->rq_dev)) { + switch (major) { + case DAC960_MAJOR+0: + disk_index = (minor & 0x00f8) >> 3; + if (disk_index < 4) + drive_stat_acct(req->cmd, req->nr_sectors, disk_index); + break; case SCSI_DISK0_MAJOR: - disk_index = (MINOR(req->rq_dev) & 0x00f0) >> 4; + disk_index = (minor & 0x00f0) >> 4; if (disk_index < 4) drive_stat_acct(req->cmd, req->nr_sectors, disk_index); break; case IDE0_MAJOR: /* same as HD_MAJOR */ case XT_DISK_MAJOR: - disk_index = (MINOR(req->rq_dev) & 0x0040) >> 6; + disk_index = (minor & 0x0040) >> 6; drive_stat_acct(req->cmd, req->nr_sectors, disk_index); break; case IDE1_MAJOR: - disk_index = ((MINOR(req->rq_dev) & 0x0040) >> 6) + 2; + disk_index = ((minor & 0x0040) >> 6) + 2; drive_stat_acct(req->cmd, req->nr_sectors, disk_index); default: break; @@ -345,10 +372,12 @@ void add_request(struct blk_dev_struct * dev, struct request * req) tmp->next = req; /* for SCSI devices, call request_fn unconditionally */ - if (scsi_blk_major(MAJOR(req->rq_dev))) + if (scsi_blk_major(major)) + queue_new_request = 1; + if (major >= COMPAQ_SMART2_MAJOR+0 && + major <= COMPAQ_SMART2_MAJOR+7) queue_new_request = 1; - if (MAJOR(req->rq_dev) >= COMPAQ_SMART2_MAJOR+0 && - MAJOR(req->rq_dev) <= COMPAQ_SMART2_MAJOR+7) + if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) queue_new_request = 1; out: if (queue_new_request) @@ -403,7 +432,7 @@ void make_request(int major,int rw, struct buffer_head * bh) unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; if (maxsector < count || maxsector - count < sector) { - bh->b_state &= (1 << BH_Lock); + bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); /* This may well happen - the kernel calls bread() without checking the size of the device, e.g., when mounting a device. */ @@ -417,7 +446,7 @@ void make_request(int major,int rw, struct buffer_head * bh) } } - rw_ahead = 0; /* normal case; gets changed below for READA/WRITEA */ + rw_ahead = 0; /* normal case; gets changed below for READA */ switch (rw) { case READA: rw_ahead = 1; @@ -428,13 +457,14 @@ void make_request(int major,int rw, struct buffer_head * bh) kstat.pgpgin++; max_req = NR_REQUEST; /* reads take precedence */ break; - case WRITEA: - rw_ahead = 1; - rw = WRITE; /* drop into WRITE */ + case WRITERAW: + rw = WRITE; + goto do_write; /* Skip the buffer refile */ case WRITE: if (!test_and_clear_bit(BH_Dirty, &bh->b_state)) goto end_io; /* Hmmph! Nothing to write */ refile_buffer(bh); + do_write: /* * We don't allow the write-requests to fill up the * queue completely: we want some room for reads, @@ -482,6 +512,8 @@ void make_request(int major,int rw, struct buffer_head * bh) case IDE5_MAJOR: case IDE6_MAJOR: case IDE7_MAJOR: + case IDE8_MAJOR: + case IDE9_MAJOR: case ACSI_MAJOR: case MFM_ACORN_MAJOR: /* @@ -508,6 +540,14 @@ void make_request(int major,int rw, struct buffer_head * bh) case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR: case SCSI_CDROM_MAJOR: + case DAC960_MAJOR+0: + case DAC960_MAJOR+1: + case DAC960_MAJOR+2: + case DAC960_MAJOR+3: + case DAC960_MAJOR+4: + case DAC960_MAJOR+5: + case DAC960_MAJOR+6: + case DAC960_MAJOR+7: case I2O_MAJOR: case COMPAQ_SMART2_MAJOR+0: case COMPAQ_SMART2_MAJOR+1: @@ -592,13 +632,6 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) struct blk_dev_struct * dev; int i; - /* Make sure that the first block contains something reasonable */ - while (!*bh) { - bh++; - if (--nr <= 0) - return; - } - dev = NULL; if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV) dev = blk_dev + major; @@ -641,33 +674,29 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) #endif } - if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) { + if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) { printk(KERN_NOTICE "Can't write to read-only device %s\n", kdevname(bh[0]->b_dev)); goto sorry; } for (i = 0; i < nr; i++) { - if (bh[i]) { - set_bit(BH_Req, &bh[i]->b_state); + set_bit(BH_Req, &bh[i]->b_state); #ifdef CONFIG_BLK_DEV_MD - if (MAJOR(bh[i]->b_dev) == MD_MAJOR) { - md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]); - continue; - } -#endif - make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]); + if (MAJOR(bh[i]->b_dev) == MD_MAJOR) { + md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]); + continue; } +#endif + make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]); } return; sorry: for (i = 0; i < nr; i++) { - if (bh[i]) { - clear_bit(BH_Dirty, &bh[i]->b_state); - clear_bit(BH_Uptodate, &bh[i]->b_state); - bh[i]->b_end_io(bh[i], 0); - } + clear_bit(BH_Dirty, &bh[i]->b_state); + clear_bit(BH_Uptodate, &bh[i]->b_state); + bh[i]->b_end_io(bh[i], 0); } return; } @@ -789,6 +818,9 @@ int __init blk_dev_init(void) #ifdef CONFIG_MAC_FLOPPY swim3_init(); #endif +#ifdef CONFIG_BLK_DEV_SWIM_IOP + swimiop_init(); +#endif #ifdef CONFIG_AMIGA_FLOPPY amiga_floppy_init(); #endif @@ -799,8 +831,9 @@ int __init blk_dev_init(void) floppy_init(); #else #if !defined(CONFIG_SGI_IP22) && !defined (__mc68000__) && \ - !defined(CONFIG_PMAC) && !defined(__sparc__) && !defined(CONFIG_APUS) \ - && !defined(CONFIG_DECSTATION) && !defined(CONFIG_BAGET_MIPS) + !defined(CONFIG_PPC) && !defined(__sparc__) && !defined(CONFIG_APUS) \ + && !defined(CONFIG_DECSTATION) && !defined(CONFIG_BAGET_MIPS) \ + && !defined(__sh__) outb_p(0xc, 0x3f2); #endif #endif diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b7987f33d..45f91b2da 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -21,6 +21,10 @@ * Make real block number available to downstream transfer functions, enables * CBC (and relatives) mode encryption requiring unique IVs per data block. * Reed H. Petty, rhp@draper.net + * + * Maximum number of loop devices now dynamic via max_loop module parameter. + * Still fixed at 8 devices when compiled into the kernel normally. + * Russell Kroll <rkroll@exploits.org> 19990701 * * Still To Fix: * - Advisory locking is ignored here. @@ -61,10 +65,11 @@ #define TIMEOUT_VALUE (6 * HZ) #include <linux/blk.h> -#define MAX_LOOP 8 -static struct loop_device loop_dev[MAX_LOOP]; -static int loop_sizes[MAX_LOOP]; -static int loop_blksizes[MAX_LOOP]; +#include <linux/malloc.h> +static int max_loop = 8; +static struct loop_device *loop_dev; +static int *loop_sizes; +static int *loop_blksizes; #define FALSE 0 #define TRUE (!FALSE) @@ -169,7 +174,7 @@ repeat: INIT_REQUEST; current_request=CURRENT; CURRENT=current_request->next; - if (MINOR(current_request->rq_dev) >= MAX_LOOP) + if (MINOR(current_request->rq_dev) >= max_loop) goto error_out; lo = &loop_dev[MINOR(current_request->rq_dev)]; if (!lo->lo_dentry || !lo->transfer) @@ -375,7 +380,7 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) a file structure */ lo->lo_backing_file = NULL; } else if (S_ISREG(inode->i_mode)) { - if (!inode->i_op->bmap) { + if (!inode->i_op->get_block) { printk(KERN_ERR "loop: device has no block access/not implemented\n"); goto out_putf; } @@ -578,7 +583,7 @@ static int lo_ioctl(struct inode * inode, struct file * file, return -ENODEV; } dev = MINOR(inode->i_rdev); - if (dev >= MAX_LOOP) + if (dev >= max_loop) return -ENODEV; lo = &loop_dev[dev]; switch (cmd) { @@ -615,7 +620,7 @@ static int lo_open(struct inode *inode, struct file *file) return -ENODEV; } dev = MINOR(inode->i_rdev); - if (dev >= MAX_LOOP) { + if (dev >= max_loop) { return -ENODEV; } lo = &loop_dev[dev]; @@ -640,7 +645,7 @@ static int lo_release(struct inode *inode, struct file *file) return 0; } dev = MINOR(inode->i_rdev); - if (dev >= MAX_LOOP) + if (dev >= max_loop) return 0; err = fsync_dev(inode->i_rdev); lo = &loop_dev[dev]; @@ -674,6 +679,8 @@ static struct file_operations lo_fops = { */ #ifdef MODULE #define loop_init init_module +MODULE_PARM(max_loop, "i"); +MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)"); #endif int loop_register_transfer(struct loop_func_table *funcs) @@ -690,7 +697,7 @@ int loop_unregister_transfer(int number) if ((unsigned)number >= MAX_LO_CRYPT) return -EINVAL; - for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) { + for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { int type = lo->lo_encrypt_type; if (type == number) { xfer_funcs[type]->release(lo); @@ -714,17 +721,46 @@ int __init loop_init(void) MAJOR_NR); return -EIO; } + + if ((max_loop < 1) || (max_loop > 255)) { + printk (KERN_WARNING "loop: max_loop must be between 1 and 255\n"); + return -EINVAL; + } + #ifndef MODULE printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR); +#else + printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop); #endif + loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL); + if (!loop_dev) { + printk (KERN_ERR "loop: Unable to create loop_dev\n"); + return -ENOMEM; + } + + loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL); + if (!loop_sizes) { + printk (KERN_ERR "loop: Unable to create loop_sizes\n"); + kfree (loop_dev); + return -ENOMEM; + } + + loop_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL); + if (!loop_blksizes) { + printk (KERN_ERR "loop: Unable to create loop_blksizes\n"); + kfree (loop_dev); + kfree (loop_sizes); + return -ENOMEM; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - for (i=0; i < MAX_LOOP; i++) { + for (i=0; i < max_loop; i++) { memset(&loop_dev[i], 0, sizeof(struct loop_device)); loop_dev[i].lo_number = i; } - memset(&loop_sizes, 0, sizeof(loop_sizes)); - memset(&loop_blksizes, 0, sizeof(loop_blksizes)); + memset(loop_sizes, 0, max_loop * sizeof(int)); + memset(loop_blksizes, 0, max_loop * sizeof(int)); blk_size[MAJOR_NR] = loop_sizes; blksize_size[MAJOR_NR] = loop_blksizes; @@ -736,5 +772,9 @@ void cleanup_module(void) { if (unregister_blkdev(MAJOR_NR, "loop") != 0) printk(KERN_WARNING "loop: cannot unregister blkdev\n"); + + kfree (loop_dev); + kfree (loop_sizes); + kfree (loop_blksizes); } #endif diff --git a/drivers/block/macide.c b/drivers/block/macide.c index 2771ea702..4f6febd28 100644 --- a/drivers/block/macide.c +++ b/drivers/block/macide.c @@ -16,7 +16,7 @@ #include <linux/interrupt.h> #include <linux/blkdev.h> #include <linux/hdreg.h> -#include <linux/zorro.h> +#include <linux/delay.h> #include <linux/ide.h> #include <asm/machw.h> @@ -68,64 +68,16 @@ static int macide_offsets[IDE_NR_PORTS] = { #define MAC_HD_ISR 0x101 - /* - * IDE interrupt glue - seems to be wired to Nubus, Slot C? - * (ROM code disassembly again) - * First try: just use Nubus interrupt for Slot C. Have Nubus code call - * a wrapper to ide_intr that checks the ISR (see above). - * Need to #define IDE_IRQ_NUBUS though. - * Alternative method: set a mac_ide_hook function pointer to the wrapper - * here and have via_do_nubus call that hook if set. - * - * Quadra needs the hook, Powerbook can use Nubus slot C. - * Checking the ISR on Quadra is done by mac_ack_intr (see Amiga code). mac_ide_intr - * mac_ide_intr is obsolete except for providing the hwgroup argument. - */ - - /* The Mac hwif data, for passing hwgroup to ide_intr */ -static ide_hwif_t *mac_hwif = NULL; - - /* The function pointer used in the Nubus handler */ -void (*mac_ide_intr_hook)(int, void *, struct pt_regs *) = NULL; - - /* - * Only purpose: feeds the hwgroup to the main IDE handler. - * Obsolete as soon as Nubus code is fixed WRT pseudo slot C int. - * (should be the case on Powerbooks) - * Alas, second purpose: feed correct irq to IDE handler (I know, - * that's cheating) :-((( - * Fix needed for interrupt code: accept Nubus ints in the regular - * request_irq code, then register Powerbook IDE as Nubus slot C, - * Quadra as slot F (F for fictious). - */ -void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - ide_intr(mac_hwif->irq, mac_hwif->hwgroup, regs); -} - - /* - * Check the interrupt status - * - * Note: In 2.0 kernels, there have been timing problems with the - * Powerbook IDE interface (BUSY was asserted too long after the - * interrupt triggered). Result: repeated errors, recalibrate etc. - * Adding a wait loop to read_intr, write_intr and set_geom_intr - * fixed the problem (waits in read/write_intr were present for Amiga - * already). - * Powerbooks were not tested with 2.1 due to lack of FPU emulation - * (thanks Apple for using LC040). If the BUSY problem resurfaces in - * 2.1, my best bet would be to add the wait loop right here, afterr - * checking the interrupt register. - */ - -static int mac_ack_intr(ide_hwif_t *hwif) +static int mac_ack_intr(ide_hwif_t* hwif) { - unsigned char ch; + unsigned char isr; + isr = readb(MAC_HD_BASE + MAC_HD_ISR); + if (isr & (1<<5)) { + writeb(isr & ~(1<<5), MAC_HD_BASE + MAC_HD_ISR); + return 1; + } - ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); - if (!(ch & 0x20)) return 0; - return 1; } /* @@ -134,34 +86,31 @@ static int mac_ack_intr(ide_hwif_t *hwif) void macide_init(void) { - hw_regs_t hw; - int index = -1; + hw_regs_t hw; + int index = -1; - if (MACH_IS_MAC) { - switch(macintosh_config->ide_type) { - case 0: - break; + if (!MACH_IS_MAC || macintosh_config->ide_type == 0) + return; + switch (macintosh_config->ide_type) { case MAC_IDE_QUADRA: - ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, - 0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR), - mac_ack_intr, IRQ_MAC_NUBUS); - index = ide_register_hw(&hw, &mac_hwif); - mac_ide_intr_hook = mac_ide_intr; - break; + ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, + 0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR), + mac_ack_intr, IRQ_NUBUS_F); + index = ide_register_hw(&hw, NULL); + break; default: ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets, - 0, 0, NULL, IRQ_MAC_NUBUS); - index = ide_register_hw(&hw, &mac_hwif); + 0, 0, NULL, IRQ_NUBUS_C); + index = ide_register_hw(&hw, NULL); break; } if (index != -1) { - if (macintosh_config->ide_type == MAC_IDE_QUADRA) - printk("ide%d: Macintosh Quadra IDE interface\n", index); - else - printk("ide%d: Macintosh Powerbook IDE interface\n", index); + if (macintosh_config->ide_type == MAC_IDE_QUADRA) + printk("ide%d: Macintosh Quadra IDE interface\n", index); + else + printk("ide%d: Macintosh Powerbook IDE interface\n", index); } - } } diff --git a/drivers/block/md.c b/drivers/block/md.c index bd610dc7b..69ff1813b 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -740,7 +740,7 @@ int md_make_request (int minor, int rw, struct buffer_head * bh) if (buffer_locked(bh)) return 0; set_bit(BH_Lock, &bh->b_state); - if (rw == WRITE || rw == WRITEA) { + if (rw == WRITE) { if (!buffer_dirty(bh)) { bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); return 0; @@ -1174,7 +1174,7 @@ struct { }; /* called from init/main.c */ -__initfunc(void md_setup(char *str,int *ints)) +void __init md_setup(char *str,int *ints) { int i; for(i=0;i<=ints[0];i++) { @@ -1186,7 +1186,7 @@ __initfunc(void md_setup(char *str,int *ints)) return; } -__initfunc(void do_md_setup(char *str,int *ints)) +void __init do_md_setup(char *str,int *ints) { int minor, pers, factor, fault; kdev_t dev; @@ -1265,7 +1265,7 @@ void raid0_init (void); void raid1_init (void); void raid5_init (void); -__initfunc(int md_init (void)) +int __init md_init (void) { printk ("md driver %d.%d.%d MAX_MD_DEV=%d, MAX_REAL=%d\n", MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION, @@ -1306,7 +1306,7 @@ __initfunc(int md_init (void)) } #ifdef CONFIG_MD_BOOT -__initfunc(void md_setup_drive(void)) +void __init md_setup_drive(void) { if(md_setup_args.set) do_md_setup(md_setup_args.str, md_setup_args.ints); diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c index 9f4c1aa92..3ab183d31 100644 --- a/drivers/block/ns87415.c +++ b/drivers/block/ns87415.c @@ -102,7 +102,7 @@ static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive) } } -__initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) +void __init ide_init_ns87415 (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; unsigned int ctrl, using_inta; diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c index 9e238803e..f05196389 100644 --- a/drivers/block/paride/paride.c +++ b/drivers/block/paride/paride.c @@ -24,7 +24,8 @@ #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/string.h> -#include <asm/spinlock.h> +#include <linux/spinlock.h> +#include <linux/wait.h> #ifdef CONFIG_PARPORT_MODULE #define CONFIG_PARPORT diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 6366afa6b..13b5f1b6a 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -142,9 +142,9 @@ static int pcd_drive_count; #include <linux/kernel.h> #include <linux/delay.h> #include <linux/cdrom.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> -#include <asm/spinlock.h> #ifndef MODULE @@ -838,21 +838,21 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMPAUSE: - { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO; } case CDROMRESUME: - { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0}; + { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO; } case CDROMPLAYMSF: - { char cmd[12]={SCMD_PLAYAUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PLAY_AUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0}; struct cdrom_msf* msf = (struct cdrom_msf*)arg; cmd[3] = msf->cdmsf_min0; @@ -867,7 +867,7 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMPLAYBLK: - { char cmd[12]={SCMD_PLAYAUDIO10,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PLAY_AUDIO_10,0,0,0,0,0,0,0,0,0,0,0}; struct cdrom_blk* blk = (struct cdrom_blk*)arg; cmd[2] = blk->from >> 24; @@ -882,7 +882,7 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMPLAYTRKIND: - { char cmd[12]={SCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0}; struct cdrom_ti* ti = (struct cdrom_ti*)arg; cmd[4] = ti->cdti_trk0; @@ -895,7 +895,7 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMREADTOCHDR: - { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0}; + { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0}; struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg; char buffer[32]; int r; @@ -910,7 +910,7 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMREADTOCENTRY: - { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0}; + { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0}; struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg; unsigned char buffer[32]; @@ -938,21 +938,21 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMSTOP: - { char cmd[12]={0x1b,1,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,0,0,0,0,0,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO; } case CDROMSTART: - { char cmd[12]={0x1b,1,0,0,1,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,1,0,0,0,0,0,0,0}; return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO; } case CDROMVOLCTRL: - { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0}; char buffer[32]; char mask[32]; struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; @@ -983,7 +983,7 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMVOLREAD: - { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0}; + { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0}; char buffer[32]; struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; int r; @@ -1004,7 +1004,7 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, case CDROMSUBCHNL: - { char cmd[12]={SCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0}; + { char cmd[12]={GPCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0}; struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; char buffer[32]; @@ -1035,7 +1035,7 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi, static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) -{ char cmd[12]={SCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0}; +{ char cmd[12]={GPCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0}; char buffer[32]; int k; int unit = DEVICE_NR(cdi->dev); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 128f9b21d..bd2839053 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -161,8 +161,8 @@ static int pd_drive_count; #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/cdrom.h> /* for the eject ioctl */ +#include <linux/spinlock.h> -#include <asm/spinlock.h> #include <asm/uaccess.h> #ifndef MODULE diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index f1cdfe3c6..58a747cb7 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -160,7 +160,7 @@ static int pf_drive_count; #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/cdrom.h> -#include <asm/spinlock.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c index 08f87655e..5bbd0c3e7 100644 --- a/drivers/block/pdc202xx.c +++ b/drivers/block/pdc202xx.c @@ -215,8 +215,8 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) byte test1, test2, speed; byte AP, BP, CP, DP, EP; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - byte udma_66 = ((id->word93 & 0x2000) && (dev->device == PCI_DEVICE_ID_PROMISE_20262)) ? 1 : 0; - byte udma_33 = ultra ? (inb((dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0; + byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; + byte udma_33 = ultra ? (inb((dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0; pci_read_config_byte(dev, 0x50, &EP); @@ -308,7 +308,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) speed = XFER_UDMA_3; } else if ((id->dma_ultra & 0x0004) && (udma_33)) { if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0404; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -319,7 +319,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) speed = XFER_UDMA_2; } else if ((id->dma_ultra & 0x0002) && (udma_33)) { if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0202; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -330,7 +330,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) speed = XFER_UDMA_1; } else if ((id->dma_ultra & 0x0001) && (udma_33)) { if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra &= ~0xFF00; drive->id->dma_ultra |= 0x0101; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; @@ -491,16 +491,16 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -__initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name)) +unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) { - unsigned long high_16 = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; byte udma_speed_flag = inb(high_16 + 0x001f); byte primary_mode = inb(high_16 + 0x001a); byte secondary_mode = inb(high_16 + 0x001b); - if (dev->rom_address) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address); + if (dev->resource[PCI_ROM_RESOURCE].start) { + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { @@ -547,9 +547,24 @@ __initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name return dev->irq; } -__initfunc(void ide_init_pdc202xx (ide_hwif_t *hwif)) +void __init ide_init_pdc202xx (ide_hwif_t *hwif) { if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; + + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20262: +#if 0 + { + unsigned long high_16 = hwif->pci_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + hwif->udma_four = 1; + } +#endif + break; + case PCI_DEVICE_ID_PROMISE_20246: + default: + hwif->udma_four = 0; + break; + } } } diff --git a/drivers/block/piix.c b/drivers/block/piix.c index 384712603..b1fd76014 100644 --- a/drivers/block/piix.c +++ b/drivers/block/piix.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/piix.c Version 0.24 June 28, 1999 + * linux/drivers/block/piix.c Version 0.25 July 11, 1999 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer @@ -149,18 +149,19 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio) #ifdef CONFIG_BLK_DEV_PIIX_TUNING -static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) +static int piix_config_drive_for_dma(ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - unsigned long flags; int sitre; short reg4042, reg44, reg48, reg4a; byte speed; int u_speed; - byte maslave = hwif->channel ? 0x42 : 0x40; + + byte maslave = hwif->channel ? 0x42 : 0x40; + int ultra = (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); int a_speed = 2 << (drive_number * 4); int u_flag = 1 << drive_number; @@ -171,9 +172,6 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) pci_read_config_word(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - save_flags(flags); - cli(); - if (id->dma_ultra && (ultra)) { if (!(reg48 & u_flag)) { pci_write_config_word(dev, 0x48, reg48|u_flag); @@ -184,7 +182,12 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) } } - if ((id->dma_ultra & 0x0004) && (ultra)) { + if ((id->dma_ultra & 0x0010) && (ultra)) { + goto backspeed; + } else if ((id->dma_ultra & 0x0008) && (ultra)) { + goto backspeed; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { +backspeed: drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; if (!((id->dma_ultra >> 8) & 4)) { @@ -256,7 +259,6 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); } - restore_flags(flags); piix_tune_drive(drive, piix_dma_2_pio(speed)); (void) ide_config_drive_speed(drive, speed); @@ -269,7 +271,8 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) printk("\n"); #endif /* PIIX_DEBUG_DRIVE_INFO */ - return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); @@ -277,10 +280,9 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - int ultra = (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0; switch (func) { case ide_dma_check: - return ide_dmaproc((ide_dma_action_t) piix_config_drive_for_dma(drive, ultra), drive); + return ide_dmaproc((ide_dma_action_t) piix_config_drive_for_dma(drive), drive); default : break; } @@ -292,12 +294,14 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive) void ide_init_piix (ide_hwif_t *hwif) { hwif->tuneproc = &piix_tune_drive; -#ifdef CONFIG_BLK_DEV_PIIX_TUNING + if (hwif->dma_base) { +#ifdef CONFIG_BLK_DEV_PIIX_TUNING hwif->dmaproc = &piix_dmaproc; - } else #endif /* CONFIG_BLK_DEV_PIIX_TUNING */ - { + hwif->drives[0].autotune = 0; + hwif->drives[1].autotune = 0; + } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index e1ff03e8f..221a3297a 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -124,7 +124,7 @@ static struct timer_list esdi_timer = {NULL, NULL, 0, 0L, ps2esdi_reset_timer}; static int reset_status; static int ps2esdi_slot = -1; int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ - +int intg_esdi = 0; /* If integrated adapter */ struct ps2esdi_i_struct { unsigned int head, sect, cyl, wpcom, lzone, ctl; }; @@ -178,7 +178,7 @@ static struct gendisk ps2esdi_gendisk = }; /* initialization routine called by ll_rw_blk.c */ -__initfunc(int ps2esdi_init(void)) +int __init ps2esdi_init(void) { /* register the device - pass the name, major number and operations @@ -244,7 +244,7 @@ cleanup_module(void) #endif /* MODULE */ /* handles boot time command line parameters */ -__initfunc(void tp720_setup(char *str, int *ints)) +void __init tp720_setup(char *str, int *ints) { /* no params, just sets the tp720esdi flag if it exists */ @@ -252,7 +252,7 @@ __initfunc(void tp720_setup(char *str, int *ints)) tp720esdi = 1; } -__initfunc(void ed_setup(char *str, int *ints)) +void __init ed_setup(char *str, int *ints) { int hdind = 0; @@ -299,7 +299,7 @@ static int ps2esdi_getinfo(char *buf, int slot, void *d) } /* ps2 esdi specific initialization - called thru the gendisk chain */ -__initfunc(static void ps2esdi_geninit(struct gendisk *ignored)) +static void __init ps2esdi_geninit(struct gendisk *ignored) { /* The first part contains the initialization code @@ -387,7 +387,7 @@ __initfunc(static void ps2esdi_geninit(struct gendisk *ignored)) reset_status = 0; reset_start = jiffies; while (!reset_status) { - esdi_timer.expires = 100; + esdi_timer.expires = HZ; esdi_timer.data = 0; esdi_timer.next = esdi_timer.prev = NULL; add_timer(&esdi_timer); @@ -401,8 +401,9 @@ __initfunc(static void ps2esdi_geninit(struct gendisk *ignored)) /* Integrated ESDI Disk and Controller has only one drive! */ - if (adapterID == INTG_ESDI_ID) /* if not "normal" PS2 ESDI adapter */ - ps2esdi_drives = 1; /* then we have only one physical disk! */ + if (adapterID == INTG_ESDI_ID) {/* if not "normal" PS2 ESDI adapter */ + ps2esdi_drives = 1; /* then we have only one physical disk! */ intg_esdi = 1; + } @@ -437,7 +438,7 @@ __initfunc(static void ps2esdi_geninit(struct gendisk *ignored)) } /* ps2esdi_geninit */ -__initfunc(static void ps2esdi_get_device_cfg(void)) +static void __init ps2esdi_get_device_cfg(void) { u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH]; @@ -560,7 +561,7 @@ static void reset_ctrl(void) /*BA */ printk("%s: hard reset...\n", DEVICE_NAME); outb_p(CTRL_HARD_RESET, ESDI_CONTROL); - expire = jiffies + 200; + expire = jiffies + 2*HZ; while (time_before(jiffies, expire)); outb_p(1, ESDI_CONTROL); } /* hard reset */ @@ -812,7 +813,8 @@ static void ps2esdi_geometry_int_handler(u_int int_ret_code) ps2esdi_info[0].wpcom = 0; ps2esdi_info[0].lzone = reply[3]; } else { - ps2esdi_drives++; + if (!intg_esdi) + ps2esdi_drives++; } } #ifdef OBSOLETE diff --git a/drivers/block/q40ide.c b/drivers/block/q40ide.c new file mode 100644 index 000000000..93d302a61 --- /dev/null +++ b/drivers/block/q40ide.c @@ -0,0 +1,109 @@ +/* + * linux/drivers/block/q40ide.c -- Q40 I/O port IDE Driver + * + * original file created 12 Jul 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * RZ: + * almost identical with pcide.c, maybe we can merge it later. + * Differences: + * max 2 HWIFS for now + * translate portaddresses to q40 native addresses (not yet...) instead rely on in/out[bw] + * address translation + * + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/hdreg.h> + +#include "ide.h" + + /* + * Bases of the IDE interfaces + */ + +#define PCIDE_NUM_HWIFS 2 + +#define PCIDE_BASE1 0x1f0 +#define PCIDE_BASE2 0x170 +#define PCIDE_BASE3 0x1e8 +#define PCIDE_BASE4 0x168 +#define PCIDE_BASE5 0x1e0 +#define PCIDE_BASE6 0x160 + +static const q40ide_ioreg_t pcide_bases[PCIDE_NUM_HWIFS] = { + PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5, + PCIDE_BASE6 */ +}; + + + /* + * Offsets from one of the above bases + */ + +#undef HD_DATA +#define HD_DATA 0x1f0 + +#define PCIDE_REG(x) ((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1)) + +static const int pcide_offsets[IDE_NR_PORTS] = { + PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR), + PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS), + PCIDE_REG(CMD) +}; + +int q40ide_default_irq(q40ide_ioreg_t base) +{ + switch (base) { + case 0x1f0: return 14; + case 0x170: return 15; + case 0x1e8: return 11; + default: + return 0; + } +} + +void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq) +{ + q40ide_ioreg_t port = base; + int i = 8; + + while (i--) + *p++ = port++; + *p++ = base + 0x206; + if (irq != NULL) + *irq = 0; +} + + + /* + * Probe for PC IDE interfaces + */ + +int q40ide_probe_hwif(int index, ide_hwif_t *hwif) +{ + static int pcide_index[PCIDE_NUM_HWIFS] = { 0, }; + int i; + + if (!MACH_IS_Q40) + return 0; + + for (i = 0; i < PCIDE_NUM_HWIFS; i++) { + if (!pcide_index[i]) { + /*printk("ide%d: Q40 IDE interface\n", index);*/ + pcide_index[i] = index+1; + } + if (pcide_index[i] == index+1) { + ide_setup_ports(hwif,(ide_ioreg_t) pcide_bases[i], pcide_offsets, 0, /*q40_ack_intr???*/ NULL); + hwif->irq = ide_default_irq((ide_ioreg_t)pcide_bases[i]); /*q40_ide_irq[i]; */ /* 14 */ + return 1; + } + } + return 0; +} diff --git a/drivers/block/raid1.c b/drivers/block/raid1.c index 7efb78400..6671f83e8 100644 --- a/drivers/block/raid1.c +++ b/drivers/block/raid1.c @@ -159,7 +159,7 @@ void raid1_end_request (struct buffer_head *bh, int uptodate) } /* - * WRITE or WRITEA. + * WRITE. */ PRINTK(("raid1_end_request(), write branch.\n")); @@ -215,15 +215,14 @@ raid1_make_request (struct md_dev *mddev, int rw, struct buffer_head * bh) memset (r1_bh, 0, sizeof (struct raid1_bh)); /* - * make_request() can abort the operation when READA or WRITEA are being + * make_request() can abort the operation when READA is being * used and no empty request is available. * * Currently, just replace the command with READ/WRITE. */ if (rw == READA) rw = READ; - if (rw == WRITEA) rw = WRITE; - if (rw == WRITE || rw == WRITEA) + if (rw == WRITE) mark_buffer_clean(bh); /* Too early ? */ /* @@ -269,7 +268,7 @@ raid1_make_request (struct md_dev *mddev, int rw, struct buffer_head * bh) } /* - * WRITE or WRITEA. + * WRITE. */ PRINTK(("raid1_make_request(n=%d), write branch.\n",n)); diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c index 3e60f92ce..83fc26fad 100644 --- a/drivers/block/raid5.c +++ b/drivers/block/raid5.c @@ -97,7 +97,7 @@ void __wait_on_stripe(struct stripe_head *sh) sh->count++; add_wait_queue(&sh->wait, &wait); repeat: - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); if (stripe_locked(sh)) { schedule(); goto repeat; @@ -1206,7 +1206,6 @@ static int raid5_make_request (struct md_dev *mddev, int rw, struct buffer_head struct stripe_head *sh; if (rw == READA) rw = READ; - if (rw == WRITEA) rw = WRITE; new_sector = raid5_compute_sector(bh->b_rsector, raid_disks, data_disks, &dd_idx, &pd_idx, raid_conf); diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 6c2768b27..7aeb3a30f 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -74,15 +74,6 @@ extern void wait_for_keypress(void); #include <linux/blk.h> #include <linux/blkpg.h> -/* - * We use a block size of 512 bytes in comparision to BLOCK_SIZE - * defined in include/linux/blk.h. This because of the finer - * granularity for filling up a RAM disk. - */ -#define RDBLK_SIZE_BITS 9 -#define RDBLK_SIZE (1<<RDBLK_SIZE_BITS) - - /* The RAM disk size is now a parameter */ #define NUM_RAMDISKS 16 /* This cannot be overridden (yet) */ @@ -114,8 +105,21 @@ static int rd_kbsize[NUM_RAMDISKS]; /* Size in blocks of 1024 bytes */ * information). */ int rd_size = 4096; /* Size of the RAM disks */ +/* + * It would be very desiderable to have a soft-blocksize (that in the case + * of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because + * doing that we'll achieve a far better MM footprint. Using a rd_blocksize of + * BLOCK_SIZE in the worst case we'll make PAGE_SIZE/BLOCK_SIZE buffer-pages + * unfreeable. With a rd_blocksize of PAGE_SIZE instead we are sure that only + * 1 page will be protected. Depending on the size of the ramdisk you + * may want to change the ramdisk blocksize to achieve a better or worse MM + * behaviour. The default is still BLOCK_SIZE (needed by rd_load_image that + * supposes the filesystem in the image uses a BLOCK_SIZE blocksize). + */ +int rd_blocksize = BLOCK_SIZE; /* Size of the RAM disks */ #ifndef MODULE + int rd_doload = 0; /* 1 = load RAM disk, 0 = don't load */ int rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */ int rd_image_start = 0; /* starting block # of image */ @@ -123,7 +127,52 @@ int rd_image_start = 0; /* starting block # of image */ unsigned long initrd_start,initrd_end; int mount_initrd = 1; /* zero if initrd should not be mounted */ int initrd_below_start_ok = 0; + +static int __init no_initrd(char *str) +{ + mount_initrd = 0; + return 1; +} + +__setup("noinitrd", no_initrd); + #endif + +static int __init ramdisk_start_setup(char *str) +{ + rd_image_start = simple_strtol(str,NULL,0); + return 1; +} + +static int __init load_ramdisk(char *str) +{ + rd_doload = simple_strtol(str,NULL,0) & 3; + return 1; +} + +static int __init prompt_ramdisk(char *str) +{ + rd_prompt = simple_strtol(str,NULL,0) & 1; + return 1; +} + +static int __init ramdisk_size(char *str) +{ + rd_size = simple_strtol(str,NULL,0); + return 1; +} + +static int __init ramdisk_size2(char *str) +{ + return ramdisk_size(str); +} + +__setup("ramdisk_start=", ramdisk_start_setup); +__setup("load_ramdisk=", load_ramdisk); +__setup("prompt_ramdisk=", prompt_ramdisk); +__setup("ramdisk=", ramdisk_size); +__setup("ramdisk_size=", ramdisk_size2); + #endif /* @@ -138,9 +187,6 @@ static void rd_request(void) unsigned long offset, len; repeat: - if (!CURRENT) - return; - INIT_REQUEST; minor = MINOR(CURRENT->rq_dev); @@ -150,8 +196,8 @@ repeat: goto repeat; } - offset = CURRENT->sector << RDBLK_SIZE_BITS; - len = CURRENT->current_nr_sectors << RDBLK_SIZE_BITS; + offset = CURRENT->sector << 9; + len = CURRENT->current_nr_sectors << 9; if ((offset + len) > rd_length[minor]) { end_request(0); @@ -197,7 +243,7 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg); + return put_user(rd_kbsize[minor] << 1, (long *) arg); case BLKROSET: case BLKROGET: @@ -297,10 +343,18 @@ static struct file_operations fd_fops = { }; /* This is the registration and initialization section of the RAM disk driver */ -__initfunc(int rd_init(void)) +int __init rd_init(void) { int i; + if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 || + (rd_blocksize & (rd_blocksize-1))) + { + printk("RAMDISK: wrong blocksize %d, reverting to defaults\n", + rd_blocksize); + rd_blocksize = BLOCK_SIZE; + } + if (register_blkdev(MAJOR_NR, "ramdisk", &fd_fops)) { printk("RAMDISK: Could not get major %d", MAJOR_NR); return -EIO; @@ -310,18 +364,19 @@ __initfunc(int rd_init(void)) for (i = 0; i < NUM_RAMDISKS; i++) { /* rd_size is given in kB */ - rd_length[i] = (rd_size << BLOCK_SIZE_BITS); - rd_hardsec[i] = RDBLK_SIZE; - rd_blocksizes[i] = BLOCK_SIZE; - rd_kbsize[i] = (rd_length[i] >> BLOCK_SIZE_BITS); + rd_length[i] = rd_size << 10; + rd_hardsec[i] = rd_blocksize; + rd_blocksizes[i] = rd_blocksize; + rd_kbsize[i] = rd_size; } hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */ blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */ blk_size[MAJOR_NR] = rd_kbsize; /* Size of the RAM disk in kB */ - printk("RAM disk driver initialized: %d RAM disks of %dK size\n", - NUM_RAMDISKS, rd_size); + printk("RAMDISK driver initialized: " + "%d RAM disks of %dK size %d blocksize\n", + NUM_RAMDISKS, rd_size, rd_blocksize); return 0; } @@ -331,7 +386,9 @@ __initfunc(int rd_init(void)) #ifdef MODULE MODULE_PARM (rd_size, "1i"); -MODULE_PARM_DESC(rd_size, "Size of each RAM disk."); +MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); +MODULE_PARM (rd_blocksize, "i"); +MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes."); int init_module(void) { @@ -370,8 +427,8 @@ void cleanup_module(void) * romfs * gzip */ -__initfunc(int -identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)) +int __init +identify_ramdisk_image(kdev_t device, struct file *fp, int start_block) { const int size = 512; struct minix_super_block *minixsb; @@ -463,7 +520,7 @@ done: /* * This routine loads in the RAM disk image. */ -__initfunc(static void rd_load_image(kdev_t device, int offset, int unit)) +static void __init rd_load_image(kdev_t device, int offset, int unit) { struct inode inode, out_inode; struct file infile, outfile; @@ -518,9 +575,15 @@ __initfunc(static void rd_load_image(kdev_t device, int offset, int unit)) goto done; } - if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) { + /* + * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so + * rd_load_image will work only with filesystem BLOCK_SIZE wide! + * So make sure to use 1k blocksize while generating ext2fs + * ramdisk-images. + */ + if (nblocks > (rd_length[unit] >> BLOCK_SIZE_BITS)) { printk("RAMDISK: image too big! (%d/%ld blocks)\n", - nblocks, rd_length[unit] >> RDBLK_SIZE_BITS); + nblocks, rd_length[unit] >> BLOCK_SIZE_BITS); goto done; } @@ -585,7 +648,7 @@ done: } -__initfunc(static void rd_load_disk(int n)) +static void __init rd_load_disk(int n) { #ifdef CONFIG_BLK_DEV_INITRD extern kdev_t real_root_dev; @@ -614,18 +677,18 @@ __initfunc(static void rd_load_disk(int n)) } -__initfunc(void rd_load(void)) +void __init rd_load(void) { rd_load_disk(0); } -__initfunc(void rd_load_secondary(void)) +void __init rd_load_secondary(void) { rd_load_disk(1); } #ifdef CONFIG_BLK_DEV_INITRD -__initfunc(void initrd_load(void)) +void __init initrd_load(void) { rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0); } @@ -684,21 +747,21 @@ static void gzip_release(void **); #include "../../lib/inflate.c" -__initfunc(static void *malloc(int size)) +static void __init *malloc(int size) { return kmalloc(size, GFP_KERNEL); } -__initfunc(static void free(void *where)) +static void __init free(void *where) { kfree(where); } -__initfunc(static void gzip_mark(void **ptr)) +static void __init gzip_mark(void **ptr) { } -__initfunc(static void gzip_release(void **ptr)) +static void __init gzip_release(void **ptr) { } @@ -707,7 +770,7 @@ __initfunc(static void gzip_release(void **ptr)) * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed. */ -__initfunc(static int fill_inbuf(void)) +static int __init fill_inbuf(void) { if (exit_code) return -1; @@ -724,7 +787,7 @@ __initfunc(static int fill_inbuf(void)) * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ -__initfunc(static void flush_window(void)) +static void __init flush_window(void) { ulg c = crc; /* temporary variable */ unsigned n; @@ -741,14 +804,14 @@ __initfunc(static void flush_window(void)) outcnt = 0; } -__initfunc(static void error(char *x)) +static void __init error(char *x) { printk(KERN_ERR "%s", x); exit_code = 1; } -__initfunc(static int -crd_load(struct file * fp, struct file *outfp)) +static int __init +crd_load(struct file * fp, struct file *outfp) { int result; diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c index ae8749813..811e1665f 100644 --- a/drivers/block/rz1000.c +++ b/drivers/block/rz1000.c @@ -33,7 +33,7 @@ #ifdef CONFIG_BLK_DEV_IDEPCI -__initfunc(void ide_init_rz1000 (ide_hwif_t *hwif)) /* called from ide-pci.c */ +void __init ide_init_rz1000 (ide_hwif_t *hwif) /* called from ide-pci.c */ { unsigned short reg; struct pci_dev *dev = hwif->pci_dev; @@ -53,7 +53,7 @@ __initfunc(void ide_init_rz1000 (ide_hwif_t *hwif)) /* called from ide-pci.c */ #else -__initfunc(static void init_rz1000 (struct pci_dev *dev, const char *name)) +static void __init init_rz1000 (struct pci_dev *dev, const char *name) { unsigned short reg, h; @@ -83,13 +83,13 @@ __initfunc(static void init_rz1000 (struct pci_dev *dev, const char *name)) } } -__initfunc(void ide_probe_for_rz100x (void)) /* called from ide.c */ +void __init ide_probe_for_rz100x (void) /* called from ide.c */ { struct pci_dev *dev = NULL; - while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev)) + while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))!=NULL) init_rz1000 (dev, "RZ1000"); - while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev)) + while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))!=NULL) init_rz1000 (dev, "RZ1001"); } diff --git a/drivers/block/sis5513.c b/drivers/block/sis5513.c new file mode 100644 index 000000000..08bbb1c91 --- /dev/null +++ b/drivers/block/sis5513.c @@ -0,0 +1,417 @@ +/* + * linux/drivers/block/sis5513.c Version 0.06 July 11, 1999 + * + * Copyright (C) 1999 Andre Hedrick + * + * drive_number + * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/blkdev.h> +#include <linux/hdreg.h> + +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include "ide_modes.h" + +static struct pci_dev *host_dev; + +#define SIS5513_DEBUG_DRIVE_INFO 0 + +extern char *ide_xfer_verbose (byte xfer_rate); + +/* + * ((id->word93 & 0x2000) && (HWIF(drive)->udma_four)) + */ +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + byte drive_pci, test1, test2, mask; + int err; + + byte speed = 0x00; + byte unmask = 0xE0; + byte four_two = 0x00; + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; + + if (host_dev) { + switch(host_dev->device) { + case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_620: + unmask = 0xF0; + four_two = 0x01; + default: + break; + } + } + + switch(drive_number) { + case 0: drive_pci = 0x40;break; + case 1: drive_pci = 0x42;break; + case 2: drive_pci = 0x44;break; + case 3: drive_pci = 0x46;break; + default: return ide_dma_off; + } + + pci_read_config_byte(dev, drive_pci, &test1); + pci_read_config_byte(dev, drive_pci|0x01, &test2); + + if ((!ultra) && (test2 & 0x80)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80); + pci_read_config_byte(dev, drive_pci|0x01, &test2); + } + + if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) { + if (!((id->dma_ultra >> 8) & 16)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x1010; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + if (!(test2 & 0x90)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|0x90); + } + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) { + if (!((id->dma_ultra >> 8) & 8)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0808; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + if (!(test2 & 0xA0)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0); + } + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + mask = (four_two) ? 0xB0 : 0xA0; + if (!(test2 & mask)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|mask); + } + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + mask = (four_two) ? 0xD0 : 0xC0; + if (!(test2 & mask)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|mask); + } + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + if (!(test2 & unmask)) { + pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); + pci_write_config_byte(dev, drive_pci|0x01, test2|unmask); + } + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + err = ide_config_drive_speed(drive, speed); + +#if SIS5513_DEBUG_DRIVE_INFO + printk("%s: %s drive%d\n", + drive->name, + ide_xfer_verbose(speed), + drive_number); +#endif /* SIS5513_DEBUG_DRIVE_INFO */ + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static void config_drive_art_rwp (ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + byte timing, pio, drive_pci, test1, test2; + + unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + + if (drive->media == ide_disk) { + struct pci_dev *dev = hwif->pci_dev; + byte reg4bh = 0; + byte rw_prefetch = (0x11 << drive_number); + + pci_read_config_byte(dev, 0x4b, ®4bh); + if ((reg4bh & rw_prefetch) != rw_prefetch) + pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); + } + + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + xfer_pio = 0; + + if (drive->id->eide_pio_iordy > 0) { + for (xfer_pio = 5; + xfer_pio>0 && + drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + xfer_pio--); + } else { + xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : + (drive->id->eide_pio_modes & 2) ? 0x04 : + (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; + } + + timing = (xfer_pio >= pio) ? xfer_pio : pio; + +/* + * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4 + * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns) + * 0x41 2:0 bits 000 110 100 011 011 + * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns) + * 0x40 3:0 bits 0000 0111 0100 0011 0001 + * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns) + */ + + switch(drive_number) { + case 0: drive_pci = 0x40;break; + case 1: drive_pci = 0x42;break; + case 2: drive_pci = 0x44;break; + case 3: drive_pci = 0x46;break; + default: return; + } + + pci_read_config_byte(dev, drive_pci, &test1); + pci_read_config_byte(dev, drive_pci|0x01, &test2); + + /* + * Do a blanket clear of active and recovery timings. + */ + + test1 &= ~0x07; + test2 &= ~0x0F; + + switch(timing) { + case 4: test1 |= 0x01;test2 |= 0x03;break; + case 3: test1 |= 0x03;test2 |= 0x03;break; + case 2: test1 |= 0x04;test2 |= 0x04;break; + case 1: test1 |= 0x07;test2 |= 0x06;break; + default: break; + } + + pci_write_config_byte(dev, drive_pci, test1); + pci_write_config_byte(dev, drive_pci|0x01, test2); +} + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_off_quietly; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + return HWIF(drive)->dmaproc(ide_dma_off, drive); + } + + if (id->field_valid & 4) { + if (id->dma_ultra & 0x001F) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive, 1); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive, 0); + } + } else if ((ide_dmaproc(ide_dma_good_drive, drive)) && + (id->eide_dma_time > 150)) { + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive, 0); + } + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * sis5513_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + */ +int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + config_drive_art_rwp(drive); + return config_drive_xfer_rate(drive); + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) +{ + struct pci_dev *host; + byte latency = 0, reg48h = 0; + + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); + pci_read_config_byte(dev, 0x48, ®48h); + + for (host = pci_devices; host; host=host->next) { + if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_620) { + if (latency != 0x10) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); + host_dev = host; + printk("%s: Chipset Core ATA-66, SiS620\n", name); + printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n", + name, + (reg48h & 0x10) ? "33" : "66", + (reg48h & 0x20) ? "33" : "66"); + break; + } else if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_530) { + host_dev = host; + printk("%s: Chipset Core ATA-66, SiS530\n", name); + printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n", + name, + (reg48h & 0x10) ? "33" : "66", + (reg48h & 0x20) ? "33" : "66"); + break; + } else if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_5600) { + host_dev = host; + printk("SIS5600:%s Chipset Core ATA-33\n", name); + break; + } else if (host->vendor == PCI_VENDOR_ID_SI && + host->device == PCI_DEVICE_ID_SI_5597) { + host_dev = host; + printk("SIS5597:%s Chipset Core ATA-33\n", name); + break; + } + } + + if (host_dev) { + byte reg52h = 0; + + pci_read_config_byte(dev, 0x52, ®52h); + if (!(reg52h & 0x04)) + pci_write_config_byte(dev, 0x52, reg52h|0x04); + } + + return 0; +} + +void __init ide_init_sis5513 (ide_hwif_t *hwif) +{ + byte reg48h = 0; + byte mask = hwif->channel ? 0x20 : 0x10; + + pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); + hwif->irq = hwif->channel ? 15 : 14; + + if (!(hwif->dma_base)) + return; + + if (host_dev) { + switch(host_dev->device) { + case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_620: + hwif->autodma = 1; + hwif->udma_four = (reg48h & mask) ? 0 : 1; + hwif->dmaproc = &sis5513_dmaproc; + return; + case PCI_DEVICE_ID_SI_5600: + case PCI_DEVICE_ID_SI_5597: + hwif->autodma = 1; + hwif->udma_four = 0; + hwif->dmaproc = &sis5513_dmaproc; + return; + default: + hwif->autodma = 0; + hwif->udma_four = 0; + return; + } + } +} diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index 2f08740ea..d4e22d33b 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -1,3 +1,14 @@ +/* + * drivers/block/sl82c105.c + * + * SL82C105/Winbond 553 IDE driver + * + * Maintainer unknown. + * + * Drive tuning added from Corel Computer's kernel sources + * -- Russell King (15/11/98) linux@arm.linux.org.uk + */ + #include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> @@ -15,9 +26,109 @@ #include "ide_modes.h" +#ifdef CONFIG_ARCH_NETWINDER +/* + * Convert a PIO mode and cycle time to the required on/off + * times for the interface. This has protection against run-away + * timings. + */ +static unsigned int get_timing_sl82c105(ide_pio_data_t *p) +{ + unsigned int cmd_on; + unsigned int cmd_off; + + cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30; + cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30; + + if (cmd_on > 32) + cmd_on = 32; + if (cmd_on == 0) + cmd_on = 1; + + if (cmd_off > 32) + cmd_off = 32; + if (cmd_off == 0) + cmd_off = 1; + + return (cmd_on - 1) << 8 | (cmd_off - 1); +} + +/* + * Tell the drive to enable the specified PIO mode. + * This should be in ide.c, maybe as a special command + * (see do_special). + */ +static int ide_set_drive_pio_mode(ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + + if (pio > 2) { + /* FIXME: I don't believe that this SELECT_DRIVE is required, + * since ide.c only calls tuneproc from do_special, after + * the correct drive has been selected. + */ + SELECT_DRIVE(hwif, drive); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + OUT_BYTE(0x08 | pio, IDE_NSECTOR_REG); + OUT_BYTE(0x03, IDE_FEATURE_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + + if (ide_wait_stat(drive, DRIVE_READY, + BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD)) { + printk("%s: drive not ready for command\n", + drive->name); + return 1; + } + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); + } + + return 0; +} + +/* + * We only deal with PIO mode here - DMA mode 'using_dma' is not + * initialised at the point that this function is called. + */ +static void tune_sl82c105(ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + ide_pio_data_t p; + unsigned int drv_ctrl = 0x909; + + pio = ide_get_best_pio_mode(drive, pio, 5, &p); + + if (!ide_set_drive_pio_mode(drive, pio)) { + drv_ctrl = get_timing_sl82c105(&p); + + if (p.use_iordy) + drv_ctrl |= 0x40; + } + + pci_write_config_word(dev, + (hwif->channel ? 0x4c : 0x44) + + (drive->select.b.unit ? 4 : 0), + drv_ctrl); + + printk("%s: selected PIO mode %d (%dns)\n", + drive->name, p.pio_mode, p.cycle_time); +} +#endif + void ide_init_sl82c105(ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; + +#ifdef CONFIG_ARCH_NETWINDER + unsigned char ctrl_stat; + + pci_read_config_byte(dev, 0x40, &ctrl_stat); + pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33); + + hwif->tuneproc = tune_sl82c105; +#else unsigned short t16; unsigned int t32; pci_read_config_word(dev, PCI_COMMAND, &t16); @@ -33,4 +144,5 @@ void ide_init_sl82c105(ide_hwif_t *hwif) printk("IDE control/status register: %08x\n",t32); pci_write_config_dword(dev, 0x40, 0x10ff08a1); #endif /* CONFIG_MBX */ +#endif } diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c new file mode 100644 index 000000000..462ef7f26 --- /dev/null +++ b/drivers/block/swim_iop.c @@ -0,0 +1,674 @@ +/* + * Driver for the SWIM (Super Woz Integrated Machine) IOP + * floppy controller on the Macintosh IIfx and Quadra 900/950 + * + * Written by Joshua M. Thompson (funaho@jurai.org) + * based on the SWIM3 driver (c) 1996 by Paul Mackerras. + * + * 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. + * + * 1999-06-12 (jmt) - Initial implementation. + */ + +/* + * ------------------- + * Theory of Operation + * ------------------- + * + * Since the SWIM IOP is message-driven we implement a simple request queue + * system. One outstanding request may be queued at any given time (this is + * an IOP limitation); only when that request has completed can a new request + * be sent. + */ + +/* This has to be defined before some of the #includes below */ + +#define MAJOR_NR FLOPPY_MAJOR + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/fd.h> +#include <linux/blk.h> +#include <linux/ioctl.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/mac_iop.h> +#include <asm/swim_iop.h> + +#define DRIVER_VERSION "Version 0.1 (1999-06-12)" + +#define MAX_FLOPPIES 4 + +#define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 + +enum swim_state { + idle, + available, + revalidating, + transferring, + ejecting +}; + +struct floppy_state { + enum swim_state state; + int drive_num; /* device number */ + int secpercyl; /* disk geometry information */ + int secpertrack; + int total_secs; + int write_prot; /* 1 if write-protected, 0 if not, -1 dunno */ + int ref_count; + struct timer_list timeout; + int ejected; + struct wait_queue *wait; + int wanted; + int timeout_pending; +}; + +struct swim_iop_req { + int sent; + int complete; + __u8 command[32]; + struct floppy_state *fs; + void (*done)(struct swim_iop_req *); +}; + +static struct swim_iop_req *current_req; +static int floppy_count; + +static struct floppy_state floppy_states[MAX_FLOPPIES]; + +static int floppy_blocksizes[2] = {512,512}; +static int floppy_sizes[2] = {2880,2880}; + +static char *drive_names[7] = { + "not installed", /* DRV_NONE */ + "unknown (1)", /* DRV_UNKNOWN */ + "a 400K drive", /* DRV_400K */ + "an 800K drive" /* DRV_800K */ + "unknown (4)", /* ???? */ + "an FDHD", /* DRV_FDHD */ + "unknown (6)", /* ???? */ + "an Apple HD20" /* DRV_HD20 */ +}; + +int swimiop_init(void); +static void swimiop_init_request(struct swim_iop_req *); +static int swimiop_send_request(struct swim_iop_req *); +static void swimiop_receive(struct iop_msg *, struct pt_regs *); +static void swimiop_status_update(int, struct swim_drvstatus *); +static int swimiop_eject(struct floppy_state *fs); + +static ssize_t floppy_read(struct file *filp, char *buf, + size_t count, loff_t *ppos); +static ssize_t floppy_write(struct file *filp, const char *buf, + size_t count, loff_t *ppos); +static int floppy_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param); +static int floppy_open(struct inode *inode, struct file *filp); +static int floppy_release(struct inode *inode, struct file *filp); +static int floppy_check_change(kdev_t dev); +static int floppy_revalidate(kdev_t dev); +static int grab_drive(struct floppy_state *fs, enum swim_state state, + int interruptible); +static void release_drive(struct floppy_state *fs); +static void set_timeout(struct floppy_state *fs, int nticks, + void (*proc)(unsigned long)); +static void fd_request_timeout(unsigned long); +static void do_fd_request(void); +static void start_request(struct floppy_state *fs); + +static struct file_operations floppy_fops = { + NULL, /* lseek */ + floppy_read, /* read */ + floppy_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + floppy_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + NULL, /* flush */ + floppy_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + floppy_check_change, /* check_media_change */ + floppy_revalidate, /* revalidate */ +}; + +/* + * SWIM IOP initialization + */ + +int swimiop_init(void) +{ + volatile struct swim_iop_req req; + struct swimcmd_status *cmd = (struct swimcmd_status *) &req.command[0]; + struct swim_drvstatus *ds = &cmd->status; + struct floppy_state *fs; + int i; + + current_req = NULL; + floppy_count = 0; + + if (!iop_ism_present) return -ENODEV; + + if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + printk(KERN_ERR "SWIM-IOP: Unable to get major %d for floppy\n", + MAJOR_NR); + return -EBUSY; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; + + printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n", + DRIVER_VERSION); + + if (iop_listen(SWIM_IOP, SWIM_CHAN, swimiop_receive, "SWIM") != 0) { + printk(KERN_ERR "SWIM-IOP: IOP channel already in use; can't initialize.\n"); + return -EBUSY; + } + + printk(KERN_ERR "SWIM_IOP: probing for installed drives.\n"); + + for (i = 0 ; i < MAX_FLOPPIES ; i++) { + memset(&floppy_states[i], 0, sizeof(struct floppy_state)); + fs = &floppy_states[floppy_count]; + + swimiop_init_request(&req); + cmd->code = CMD_STATUS; + cmd->drive_num = i + 1; + if (swimiop_send_request(&req) != 0) continue; + while (!req.complete); + if (cmd->error != 0) { + printk(KERN_ERR "SWIM-IOP: probe on drive %d returned error %d\n", i, (uint) cmd->error); + continue; + } + if (ds->installed != 0x01) continue; + printk("SWIM-IOP: drive %d is %s (%s, %s, %s, %s)\n", i, + drive_names[ds->info.type], + ds->info.external? "ext" : "int", + ds->info.scsi? "scsi" : "floppy", + ds->info.fixed? "fixed" : "removable", + ds->info.secondary? "secondary" : "primary"); + swimiop_status_update(floppy_count, ds); + fs->state = idle; + + init_timer(&fs->timeout); + floppy_count++; + } + printk("SWIM-IOP: detected %d installed drives.\n", floppy_count); + + do_floppy = NULL; + + return 0; +} + +static void swimiop_init_request(struct swim_iop_req *req) +{ + req->sent = 0; + req->complete = 0; + req->done = NULL; +} + +static int swimiop_send_request(struct swim_iop_req *req) +{ + unsigned long cpu_flags; + int err; + + /* It's doubtful an interrupt routine would try to send */ + /* a SWIM request, but I'd rather play it safe here. */ + + save_flags(cpu_flags); + cli(); + + if (current_req != NULL) { + restore_flags(cpu_flags); + return -ENOMEM; + } + + current_req = req; + + /* Interrupts should be back on for iop_send_message() */ + + restore_flags(cpu_flags); + + err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req, + sizeof(req->command), (__u8 *) &req->command[0], + swimiop_receive); + + /* No race condition here; we own current_req at this point */ + + if (err) { + current_req = NULL; + } else { + req->sent = 1; + } + return err; +} + +/* + * Receive a SWIM message from the IOP. + * + * This will be called in two cases: + * + * 1. A message has been successfully sent to the IOP. + * 2. An unsolicited message was received from the IOP. + */ + +void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs) +{ + struct swim_iop_req *req; + struct swimmsg_status *sm; + struct swim_drvstatus *ds; + + req = current_req; + + switch(msg->status) { + case IOP_MSGSTATUS_COMPLETE: + memcpy(&req->command[0], &msg->reply[0], sizeof(req->command)); + req->complete = 1; + if (req->done) (*req->done)(req); + current_req = NULL; + break; + case IOP_MSGSTATUS_UNSOL: + sm = (struct swimmsg_status *) &msg->message[0]; + ds = &sm->status; + swimiop_status_update(sm->drive_num, ds); + iop_complete_message(msg); + break; + } +} + +static void swimiop_status_update(int drive_num, struct swim_drvstatus *ds) +{ + struct floppy_state *fs = &floppy_states[drive_num]; + + fs->write_prot = (ds->write_prot == 0x80); + if ((ds->disk_in_drive != 0x01) && (ds->disk_in_drive != 0x02)) { + fs->ejected = 1; + } else { + fs->ejected = 0; + } + switch(ds->info.type) { + case DRV_400K: + fs->secpercyl = 10; + fs->secpertrack = 10; + fs->total_secs = 800; + break; + case DRV_800K: + fs->secpercyl = 20; + fs->secpertrack = 10; + fs->total_secs = 1600; + break; + case DRV_FDHD: + fs->secpercyl = 36; + fs->secpertrack = 18; + fs->total_secs = 2880; + break; + default: + fs->secpercyl = 0; + fs->secpertrack = 0; + fs->total_secs = 0; + break; + } +} + +static int swimiop_eject(struct floppy_state *fs) +{ + int err, n; + struct swim_iop_req req; + struct swimcmd_eject *cmd = (struct swimcmd_eject *) &req.command[0]; + + err = grab_drive(fs, ejecting, 1); + if (err) return err; + + swimiop_init_request(&req); + cmd->code = CMD_EJECT; + cmd->drive_num = fs->drive_num; + err = swimiop_send_request(&req); + if (err) { + release_drive(fs); + return err; + } + for (n = 2*HZ; n > 0; --n) { + if (req.complete) break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + release_drive(fs); + return cmd->error; +} + +static ssize_t floppy_read(struct file *filp, char *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + fs = &floppy_states[devnum]; + if (fs->ejected) + return -ENXIO; + return block_read(filp, buf, count, ppos); +} + +static ssize_t floppy_write(struct file * filp, const char * buf, + size_t count, loff_t *ppos) +{ + struct inode * inode = filp->f_dentry->d_inode; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + check_disk_change(inode->i_rdev); + fs = &floppy_states[devnum]; + if (fs->ejected) + return -ENXIO; + if (fs->write_prot) + return -EROFS; + return block_write(filp, buf, count, ppos); +} + +static struct floppy_struct floppy_type = + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ + +static int floppy_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ + struct floppy_state *fs; + int err; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) || + ((cmd & 0x80) && !suser())) + return -EPERM; + + fs = &floppy_states[devnum]; + + switch (cmd) { + case FDEJECT: + if (fs->ref_count != 1) + return -EBUSY; + err = swimiop_eject(fs); + return err; + case FDGETPRM: + err = copy_to_user((void *) param, (void *) &floppy_type, + sizeof(struct floppy_struct)); + return err; + } + return -ENOIOCTLCMD; +} + +static int floppy_open(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int err; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + if (filp == 0) + return -EIO; + + fs = &floppy_states[devnum]; + err = 0; + if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; + + if (err == 0 && (filp->f_flags & O_NDELAY) == 0 + && (filp->f_mode & 3)) { + check_disk_change(inode->i_rdev); + if (fs->ejected) + err = -ENXIO; + } + + if (err == 0 && (filp->f_mode & 2)) { + if (fs->write_prot) + err = -EROFS; + } + + if (err) return err; + + if (filp->f_flags & O_EXCL) + fs->ref_count = -1; + else + ++fs->ref_count; + + /* Allow ioctls if we have write-permissions even if read-only open */ + if ((filp->f_mode & 2) || (permission(inode, 2) == 0)) + filp->f_mode |= IOCTL_MODE_BIT; + if (filp->f_mode & 2) + filp->f_mode |= OPEN_WRITE_BIT; + + return 0; +} + +static int floppy_release(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + /* + * If filp is NULL, we're being called from blkdev_release + * or after a failed mount attempt. In the former case the + * device has already been sync'ed, and in the latter no + * sync is required. Otherwise, sync if filp is writable. + */ + if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) + block_fsync (filp, filp->f_dentry); + + fs = &floppy_states[devnum]; + if (fs->ref_count > 0) fs->ref_count--; + return 0; +} + +static int floppy_check_change(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + return fs->ejected; +} + +static int floppy_revalidate(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + + grab_drive(fs, revalidating, 0); + /* yadda, yadda */ + release_drive(fs); + + return 0; +} + +static void floppy_off(unsigned int nr) +{ +} + +static int grab_drive(struct floppy_state *fs, enum swim_state state, + int interruptible) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (fs->state != idle) { + ++fs->wanted; + while (fs->state != available) { + if (interruptible && signal_pending(current)) { + --fs->wanted; + restore_flags(flags); + return -EINTR; + } + interruptible_sleep_on(&fs->wait); + } + --fs->wanted; + } + fs->state = state; + restore_flags(flags); + return 0; +} + +static void release_drive(struct floppy_state *fs) +{ + unsigned long flags; + + save_flags(flags); + cli(); + fs->state = idle; + start_request(fs); + restore_flags(flags); +} + +static void set_timeout(struct floppy_state *fs, int nticks, + void (*proc)(unsigned long)) +{ + unsigned long flags; + + save_flags(flags); cli(); + if (fs->timeout_pending) + del_timer(&fs->timeout); + fs->timeout.expires = jiffies + nticks; + fs->timeout.function = proc; + fs->timeout.data = (unsigned long) fs; + add_timer(&fs->timeout); + fs->timeout_pending = 1; + restore_flags(flags); +} + +static void do_fd_request(void) +{ + int i; + + for (i = 0 ; i < floppy_count ; i++) { + start_request(&floppy_states[i]); + } +} + +static void fd_request_complete(struct swim_iop_req *req) +{ + struct floppy_state *fs = req->fs; + struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req->command[0]; + + del_timer(&fs->timeout); + fs->timeout_pending = 0; + fs->state = idle; + if (cmd->error) { + printk(KERN_ERR "SWIM-IOP: error %d on read/write request.\n", cmd->error); + end_request(0); + } else { + CURRENT->sector += cmd->num_blocks; + CURRENT->current_nr_sectors -= cmd->num_blocks; + if (CURRENT->current_nr_sectors <= 0) { + end_request(1); + return; + } + } + start_request(fs); +} + +static void fd_request_timeout(unsigned long data) +{ + struct floppy_state *fs = (struct floppy_state *) data; + + fs->timeout_pending = 0; + end_request(0); + fs->state = idle; +} + +static void start_request(struct floppy_state *fs) +{ + volatile struct swim_iop_req req; + struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req.command[0]; + + if (fs->state == idle && fs->wanted) { + fs->state = available; + wake_up(&fs->wait); + return; + } + while (CURRENT && fs->state == idle) { + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + if (CURRENT->bh && !buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); +#if 0 + printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n", + kdev_t_to_nr(CURRENT->rq_dev), CURRENT->cmd, + CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer); + printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n", + CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors); +#endif + + if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) { + end_request(0); + continue; + } + if (CURRENT->current_nr_sectors == 0) { + end_request(1); + continue; + } + if (fs->ejected) { + end_request(0); + continue; + } + + swimiop_init_request(&req); + req.fs = fs; + req.done = fd_request_complete; + + if (CURRENT->cmd == WRITE) { + if (fs->write_prot) { + end_request(0); + continue; + } + cmd->code = CMD_WRITE; + } else { + cmd->code = CMD_READ; + + } + cmd->drive_num = fs->drive_num; + cmd->buffer = CURRENT->buffer; + cmd->first_block = CURRENT->sector; + cmd->num_blocks = CURRENT->current_nr_sectors; + + if (swimiop_send_request(&req)) { + end_request(0); + continue; + } + + set_timeout(fs, HZ*CURRENT->current_nr_sectors, + fd_request_timeout); + + fs->state = transferring; + } +} diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index c4f96d492..ad6a75d0f 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -212,7 +212,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) /* * Invoked from ide-dma.c at boot time. */ -__initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) +void __init ide_init_trm290 (ide_hwif_t *hwif) { unsigned int cfgbase = 0; unsigned long flags; @@ -220,7 +220,7 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) struct pci_dev *dev = hwif->pci_dev; hwif->chipset = ide_trm290; - cfgbase = dev->base_address[4]; + cfgbase = dev->resource[4].start; if ((dev->class & 5) && cfgbase) { hwif->config_data = cfgbase & PCI_BASE_ADDRESS_IO_MASK; @@ -263,7 +263,16 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) old = inw(hwif->config_data) & ~1; if (old != compat && inb(old+2) == 0xff) { compat += (next_offset += 0x400); /* leave lower 10 bits untouched */ - hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; /* FIXME: should do a check_region */ +#if 1 + if (ide_check_region(compat + 2, 1)) + printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2)); + /* + * The region check is not needed; however......... + * Since this is the checked in ide-probe.c, + * this is only an assignment. + */ +#endif + hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; outw(compat|1, hwif->config_data); printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1); } diff --git a/drivers/block/via82c586.c b/drivers/block/via82c586.c index 7dd6eb321..e5697014e 100644 --- a/drivers/block/via82c586.c +++ b/drivers/block/via82c586.c @@ -1,8 +1,8 @@ /* - * linux/drivers/block/via82c586.c Version 0.03 Nov. 19, 1998 + * linux/drivers/block/via82c586.c Version 0.04 July 11, 1999 * * Copyright (C) 1998 Michel Aubry, Maintainer - * Copyright (C) 1998 Andre Hedrick, Integrater + * Copyright (C) 1998 Andre Hedrick, Maintainer * * The VIA MVP-3 is reported OK with UDMA. * The TX Pro III is also reported OK with UDMA. @@ -57,6 +57,9 @@ #include <asm/io.h> +static struct pci_dev *host_dev; +static struct pci_dev *isa_dev; + #define DISPLAY_VIA_TIMINGS #if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) @@ -438,6 +441,137 @@ static int via_set_fifoconfig(ide_hwif_t *hwif) return 0; } +unsigned int __init pci_init_via82c568 (struct pci_dev *dev, const char *name) +{ + struct pci_dev *host; + struct pci_dev *isa; + + byte revision = 0; + + for (host = pci_devices; host; host=host->next) { + if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C585) { + host_dev = host; + printk("VT 82C585 Apollo VP1/VPX"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C595) { + host_dev = host; + printk("VT 82C595 Apollo VP2"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C597_0) { + host_dev = host; + printk("VT 82C597 Apollo VP3"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C598_0) { + host_dev = host; + printk("VT 82C598 Apollo MVP3"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } else if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C596) { + isa_dev = isa; + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C680) { + host_dev = host; + printk("VT 82C680 Apollo P6"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C586_1) { + isa_dev = isa; + pci_read_config_byte(isa_dev, 0x0d, &revision); + if (revision >= 0x20) + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C691) { + host_dev = host; + printk("VT 82C691 Apollo Pro"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C596) { + isa_dev = isa; + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } else if (host->vendor == PCI_VENDOR_ID_VIA && + host->device == PCI_DEVICE_ID_VIA_82C693) { + host_dev = host; + printk("VT 82C693 Apollo Pro Plus"); + for (isa = pci_devices; isa; isa=isa->next) { + if (isa->vendor == PCI_VENDOR_ID_VIA && + isa->device == PCI_DEVICE_ID_VIA_82C596) { + isa_dev = isa; + printk(" Chipset Core ATA-33"); + break; + } + } + printk("\n"); + break; + } + } + return 0; +} + +void __init ide_init_via82c586 (ide_hwif_t *hwif) +{ + set_via_timings(hwif); +} + /* * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) * checks if channel "channel" of if hwif is dma @@ -464,9 +598,3 @@ void ide_dmacapable_via82c586 (ide_hwif_t *hwif, unsigned long dmabase) ide_setup_dma(hwif, dmabase, 8); } } - -__initfunc(void ide_init_via82c586 (ide_hwif_t *hwif)) -{ - set_via_timings(hwif); -} - diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 04c88fb08..44e8317f0 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -55,7 +55,7 @@ #define XD_DONT_USE_DMA 0 /* Initial value. may be overriden using "nodma" module option */ -#define XD_INIT_DISK_DELAY 3 /* 30 ms delay during disk initialization */ +#define XD_INIT_DISK_DELAY (30*HZ/1000) /* 30 ms delay during disk initialization */ /* Above may need to be increased if a problem with the 2nd drive detection (ST11M controller) or resetting a controler (WD) appears */ @@ -179,7 +179,7 @@ static volatile u_char xd_error; static int nodma = XD_DONT_USE_DMA; /* xd_init: register the block device number and set up pointer tables */ -__initfunc(int xd_init (void)) +int __init xd_init (void) { if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) { printk("xd: Unable to get major number %d\n",MAJOR_NR); @@ -194,7 +194,7 @@ __initfunc(int xd_init (void)) } /* xd_detect: scan the possible BIOS ROM locations for the signature strings */ -__initfunc(static u_char xd_detect (u_char *controller, unsigned int *address)) +static u_char __init xd_detect (u_char *controller, unsigned int *address) { u_char i,j,found = 0; @@ -218,7 +218,7 @@ __initfunc(static u_char xd_detect (u_char *controller, unsigned int *address)) /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */ /* and set up the "raw" device entries in the table */ -__initfunc(static void xd_geninit (struct gendisk *ignored)) +static void __init xd_geninit (struct gendisk *ignored) { u_char i,controller; unsigned int address; @@ -686,7 +686,7 @@ static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outd return (csb & CSB_ERROR); } -__initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive))) +static u_char __init xd_initdrives (void (*init_drive)(u_char drive)) { u_char cmdblk[6],i,count = 0; @@ -708,14 +708,14 @@ __initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive))) return (count); } -__initfunc(static void xd_manual_geo_set (u_char drive)) +static void __init xd_manual_geo_set (u_char drive) { xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]); xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]); xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]); } -__initfunc(static void xd_dtc_init_controller (unsigned int address)) +static void __init xd_dtc_init_controller (unsigned int address) { switch (address) { case 0x00000: @@ -732,7 +732,7 @@ __initfunc(static void xd_dtc_init_controller (unsigned int address)) } -__initfunc(static void xd_dtc5150cx_init_drive (u_char drive)) +static void __init xd_dtc5150cx_init_drive (u_char drive) { /* values from controller's BIOS - BIOS chip may be removed */ static u_short geometry_table[][4] = { @@ -779,7 +779,7 @@ __initfunc(static void xd_dtc5150cx_init_drive (u_char drive)) xd_recalibrate(drive); } -__initfunc(static void xd_dtc_init_drive (u_char drive)) +static void __init xd_dtc_init_drive (u_char drive) { u_char cmdblk[6],buf[64]; @@ -806,7 +806,7 @@ __initfunc(static void xd_dtc_init_drive (u_char drive)) printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive); } -__initfunc(static void xd_wd_init_controller (unsigned int address)) +static void __init xd_wd_init_controller (unsigned int address) { switch (address) { case 0x00000: @@ -828,7 +828,7 @@ __initfunc(static void xd_wd_init_controller (unsigned int address)) sleep_on(&xdc_wait); } -__initfunc(static void xd_wd_init_drive (u_char drive)) +static void __init xd_wd_init_drive (u_char drive) { /* values from controller's BIOS - BIOS may be disabled */ static u_short geometry_table[][4] = { @@ -912,7 +912,7 @@ __initfunc(static void xd_wd_init_drive (u_char drive)) } -__initfunc(static void xd_seagate_init_controller (unsigned int address)) +static void __init xd_seagate_init_controller (unsigned int address) { switch (address) { case 0x00000: @@ -928,7 +928,7 @@ __initfunc(static void xd_seagate_init_controller (unsigned int address)) outb(0,XD_RESET); /* reset the controller */ } -__initfunc(static void xd_seagate_init_drive (u_char drive)) +static void __init xd_seagate_init_drive (u_char drive) { u_char cmdblk[6],buf[0x200]; @@ -944,7 +944,7 @@ __initfunc(static void xd_seagate_init_drive (u_char drive)) } /* Omti support courtesy Dirk Melchers */ -__initfunc(static void xd_omti_init_controller (unsigned int address)) +static void __init xd_omti_init_controller (unsigned int address) { switch (address) { case 0x00000: @@ -961,7 +961,7 @@ __initfunc(static void xd_omti_init_controller (unsigned int address)) outb(0,XD_RESET); /* reset the controller */ } -__initfunc(static void xd_omti_init_drive (u_char drive)) +static void __init xd_omti_init_drive (u_char drive) { /* gets infos from drive */ xd_override_init_drive(drive); @@ -971,7 +971,7 @@ __initfunc(static void xd_omti_init_drive (u_char drive)) } /* Xebec support (AK) */ -__initfunc(static void xd_xebec_init_controller (unsigned int address)) +static void __init xd_xebec_init_controller (unsigned int address) { /* iobase may be set manually in range 0x300 - 0x33C irq may be set manually to 2(9),3,4,5,6,7 @@ -1004,7 +1004,7 @@ If you need non-standard settings use the xd=... command */ sleep_on(&xdc_wait); } -__initfunc(static void xd_xebec_init_drive (u_char drive)) +static void __init xd_xebec_init_drive (u_char drive) { /* values from controller's BIOS - BIOS chip may be removed */ static u_short geometry_table[][5] = { @@ -1047,7 +1047,7 @@ __initfunc(static void xd_xebec_init_drive (u_char drive)) /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */ -__initfunc(static void xd_override_init_drive (u_char drive)) +static void __init xd_override_init_drive (u_char drive) { u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 }; u_char cmdblk[6],i; @@ -1074,7 +1074,7 @@ __initfunc(static void xd_override_init_drive (u_char drive)) } /* xd_setup: initialise controler from command line parameters */ -__initfunc(void xd_setup (char *command,int *integers)) +void __init xd_setup (char *command,int *integers) { switch (integers[0]) { case 4: if (integers[4] < 0) @@ -1097,7 +1097,7 @@ __initfunc(void xd_setup (char *command,int *integers)) #ifndef MODULE /* xd_manual_geo_init: initialise drive geometry from command line parameters (used only for WD drives) */ -__initfunc(void xd_manual_geo_init (char *command,int *integers)) +void __init xd_manual_geo_init (char *command,int *integers) { int i; if (integers[0]%3 != 0) { @@ -1110,7 +1110,7 @@ __initfunc(void xd_manual_geo_init (char *command,int *integers)) #endif /* MODULE */ /* xd_setparam: set the drive characteristics */ -__initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)) +static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc) { u_char cmdblk[14]; @@ -1204,5 +1204,10 @@ void cleanup_module(void) xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200); } } +#else + +__setup ("xd=", xd_setup); +__setup ("xd_geo=", xd_manual_geo_init); + #endif /* MODULE */ diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index f863a8326..f75150e4a 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -27,28 +27,22 @@ #define MAJOR_NR Z2RAM_MAJOR -#include <linux/config.h> #include <linux/major.h> #include <linux/malloc.h> #include <linux/blk.h> #include <linux/init.h> - -#if defined(MODULE) #include <linux/module.h> -#endif #include <asm/setup.h> #include <asm/bitops.h> #include <asm/amigahw.h> -#ifdef CONFIG_APUS #include <asm/pgtable.h> #include <asm/io.h> -#endif #include <linux/zorro.h> -extern int num_memory; -extern struct mem_info memory[NUM_MEMINFO]; +extern int m68k_realnum_memory; +extern struct mem_info m68k_memory[NUM_MEMINFO]; #define TRUE (1) #define FALSE (0) @@ -191,14 +185,14 @@ z2_open( struct inode *inode, struct file *filp ) int index = device - Z2MINOR_MEMLIST1 + 1; unsigned long size, paddr, vaddr; - if (index >= num_memory) { + if (index >= m68k_realnum_memory) { printk( KERN_ERR DEVICE_NAME ": no such entry in z2ram_map\n" ); return -ENOMEM; } - paddr = memory[index].addr; - size = memory[index].size & ~(Z2RAM_CHUNKSIZE-1); + paddr = m68k_memory[index].addr; + size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1); #ifdef __powerpc__ /* FIXME: ioremap doesn't build correct memory tables. */ @@ -212,8 +206,7 @@ z2_open( struct inode *inode, struct file *filp ) _PAGE_WRITETHRU); #else - vaddr = kernel_map (paddr, size, KERNELMAP_FULL_CACHING, - NULL); + vaddr = (unsigned long)ioremap(paddr, size); #endif z2ram_map = kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]), @@ -316,9 +309,7 @@ z2_open( struct inode *inode, struct file *filp ) blk_size[ MAJOR_NR ] = z2_sizes; } -#if defined(MODULE) MOD_INC_USE_COUNT; -#endif return 0; } @@ -331,9 +322,11 @@ z2_release( struct inode *inode, struct file *filp ) sync_dev( inode->i_rdev ); -#if defined(MODULE) + /* + * FIXME: unmap memory + */ + MOD_DEC_USE_COUNT; -#endif return 0; } @@ -356,8 +349,8 @@ static struct file_operations z2_fops = NULL, /* revalidate */ }; -__initfunc(int -z2_init( void )) +int __init +z2_init( void ) { if ( !MACH_IS_AMIGA ) |