Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
- Version 2.2.7 for Linux 2.2.16
- Version 2.4.7 for Linux 2.4.0
+ Version 2.2.8 for Linux 2.2.16
+ Version 2.4.8 for Linux 2.4.0
PRODUCTION RELEASE
- 1 August 2000
+ 19 August 2000
Leonard N. Zubkoff
Dandelion Digital
well as the most recent release of this driver, will always be available from
my Linux Home Page at URL "http://www.dandelion.com/Linux/". The Linux DAC960
driver supports all current Mylex PCI RAID controllers including the new
-eXtremeRAID 2000/3000 and AcceleRAID 352/170 models which have an entirely new
-firmware interface from the older eXtremeRAID 1100, AcceleRAID 150/200/250, and
-DAC960PJ/PG/PU/PD/PL. See below for a complete controller list as well as
+eXtremeRAID 2000/3000 and AcceleRAID 352/170/160 models which have an entirely
+new firmware interface from the older eXtremeRAID 1100, AcceleRAID 150/200/250,
+and DAC960PJ/PG/PU/PD/PL. See below for a complete controller list as well as
minimum firmware version requirements. For simplicity, in most places this
documentation refers to DAC960 generically rather than explicitly listing all
the supported models.
100MHz Intel i960RM RISC Processor
16MB/32MB/64MB ECC SDRAM Memory
+AcceleRAID 160
+ 1 Wide Ultra-160 LVD SCSI channel
+ 100MHz Intel i960RS RISC Processor
+ Built in 16M ECC SDRAM Memory
+ PCI Low Profile Form Factor - fit for 2U height
+
eXtremeRAID 1100 (DAC1164P)
3 Wide Ultra-2/LVD SCSI channels
233MHz StrongARM SA 110 Processor
Intel i960 RISC Processor
2MB/4MB/8MB/16MB/32MB DRAM Memory
-For the eXtremeRAID 2000/3000 and AcceleRAID 352/170, firmware version 6.00-01
-or above is required.
+For the eXtremeRAID 2000/3000 and AcceleRAID 352/170/160, firmware version
+6.00-01 or above is required.
For the eXtremeRAID 1100, firmware version 5.06-0-52 or above is required.
replacing "/usr/src" with wherever you keep your Linux kernel source tree:
cd /usr/src
- tar -xvzf DAC960-2.2.7.tar.gz (or DAC960-2.4.7.tar.gz)
+ tar -xvzf DAC960-2.2.8.tar.gz (or DAC960-2.4.8.tar.gz)
mv README.DAC960 linux/Documentation
mv DAC960.[ch] linux/drivers/block
- patch -p0 < DAC960.patch
+ patch -p0 < DAC960.patch (if DAC960.patch is included)
cd linux
make config
make depend
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 17
-EXTRAVERSION = pre19
+EXTRAVERSION = pre20
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
}
printk("\nCall Trace: ");
if (!esp || (esp & 3))
- printk("Bad EIP value.");
+ printk("Bad ESP value.");
else {
stack = (unsigned long *) esp;
i = 1;
*/
-#define DAC960_DriverVersion "2.2.7"
-#define DAC960_DriverDate "1 August 2000"
+#define DAC960_DriverVersion "2.2.8"
+#define DAC960_DriverDate "19 August 2000"
#include <linux/version.h>
Controller->Bus = Bus;
Controller->Device = Device;
Controller->Function = Function;
- sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
/*
Map the Controller Register Window.
*/
{ 0x008D, "M Rebuild Failed for Unknown Reasons" },
{ 0x008E, "M Rebuild Failed due to New Physical Device" },
{ 0x008F, "M Rebuild Failed due to Logical Drive Failure" },
- { 0x0090, "L Initialization Started" },
- { 0x0091, "L Initialization Completed" },
- { 0x0092, "L Initialization Cancelled" },
- { 0x0093, "L Initialization Failed" },
+ { 0x0090, "M Initialization Started" },
+ { 0x0091, "M Initialization Completed" },
+ { 0x0092, "M Initialization Cancelled" },
+ { 0x0093, "M Initialization Failed" },
{ 0x0094, "L Found" },
{ 0x0095, "L Gone" },
- { 0x0096, "L Expand Capacity Started" },
- { 0x0097, "L Expand Capacity Completed" },
- { 0x0098, "L Expand Capacity Failed" },
+ { 0x0096, "M Expand Capacity Started" },
+ { 0x0097, "M Expand Capacity Completed" },
+ { 0x0098, "M Expand Capacity Failed" },
{ 0x0099, "L Bad Block Found" },
{ 0x009A, "L Size Changed" },
{ 0x009B, "L Type Changed" },
{ 0, "" } };
int EventListIndex = 0, EventCode;
unsigned char EventType, *EventMessage;
+ if (Event->EventCode == 0x1C &&
+ RequestSense->SenseKey == DAC960_SenseKey_VendorSpecific &&
+ (RequestSense->AdditionalSenseCode == 0x80 ||
+ RequestSense->AdditionalSenseCode == 0x81))
+ Event->EventCode = ((RequestSense->AdditionalSenseCode - 0x80) << 8) |
+ RequestSense->AdditionalSenseCodeQualifier;
while (true)
{
EventCode = EventList[EventListIndex].EventCode;
RequestSense->CommandSpecificInformation[3]);
break;
case 'E':
+ if (Controller->SuppressEnclosureMessages) break;
sprintf(MessageBuffer, EventMessage, Event->LogicalUnit);
DAC960_Critical("Enclosure %d %s\n", Controller,
Event->TargetID, MessageBuffer);
LogicalDeviceSize);
else if (NewLogicalDeviceInfo->BackgroundInitializationInProgress)
DAC960_V2_ReportProgress(Controller,
- "BackgroundInitialization",
+ "Background Initialization",
LogicalDeviceNumber,
NewLogicalDeviceInfo
->BackgroundInitializationBlockNumber,
DiskGeometry_T Geometry, *UserGeometry;
DAC960_Controller_T *Controller;
int PartitionNumber;
+ if (File == NULL) return -EINVAL;
if (File->f_flags & O_NONBLOCK)
return DAC960_UserIOCTL(Inode, File, Request, Argument);
if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
ErrorCode =
copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T));
if (ErrorCode != 0) goto Failure1;
+ if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL;
if (!((DataTransferLength == 0 &&
DCDB.Direction
== DAC960_V1_DCDB_NoDataTransfer) ||
if (CommandOpcode == DAC960_V1_DCDB)
{
DCDB = KernelCommand->DCDB;
+ if (DCDB->Channel >= DAC960_V1_MaxChannels) return -EINVAL;
if (!((DataTransferLength == 0 &&
DCDB->Direction == DAC960_V1_DCDB_NoDataTransfer) ||
(DataTransferLength > 0 &&
== DAC960_V2_NormalCompletion
? "Cancelled" : "Not Cancelled"));
}
+ else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0)
+ Controller->SuppressEnclosureMessages = true;
else DAC960_UserCritical("Illegal User Command: '%s'\n",
Controller, UserCommand);
DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry;
PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry;
if (Controller == NULL) continue;
+ sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
ControllerProcEntry = &Controller->ControllerProcEntry;
ControllerProcEntry->name = Controller->ControllerName;
ControllerProcEntry->namelen = strlen(ControllerProcEntry->name);
extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument);
-/*
- Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses.
-*/
-
-static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress)
-{
- return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress);
-}
-
-
-/*
- Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses.
-*/
-
-static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress)
-{
- return (void *) bus_to_virt(BusAddress);
-}
-
-
/*
DAC960_DriverVersion protects the private portion of this file.
*/
boolean EphemeralProgressMessage;
boolean DriveSpinUpMessageDisplayed;
boolean MonitoringAlertMode;
+ boolean SuppressEnclosureMessages;
Timer_T MonitoringTimer;
GenericDiskInfo_T GenericDiskInfo;
DAC960_Command_T *FreeCommands;
}
+/*
+ Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses.
+*/
+
+static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress)
+{
+ return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress);
+}
+
+
+/*
+ Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses.
+*/
+
+static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress)
+{
+ return (void *) bus_to_virt(BusAddress);
+}
+
+
/*
Define the DAC960 BA Series Controller Interface Register Offsets.
*/
fi
dep_tristate 'Crystal CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND
-dep_tristate 'Crystal SoundFusion (CS461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
+dep_tristate 'Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
dep_tristate 'Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
if [ "$CONFIG_SOUND_ES1370" = "y" ]; then
static int ac97_init_mixer(struct ac97_codec *codec);
static int sigmatel_init(struct ac97_codec *codec);
+static int enable_eapd(struct ac97_codec *codec);
#define arraysize(x) (sizeof(x)/sizeof((x)[0]))
} ac97_codec_ids[] = {
{0x414B4D00, "Asahi Kasei AK4540" , NULL},
{0x41445340, "Analog Devices AD1881" , NULL},
+ {0x41445360, "Analog Devices AD1885" , enable_eapd},
{0x43525900, "Cirrus Logic CS4297" , NULL},
{0x43525903, "Cirrus Logic CS4297" , NULL},
{0x43525913, "Cirrus Logic CS4297A" , NULL},
return 1;
}
+/*
+ * Bring up an AD1885
+ */
+
+static int enable_eapd(struct ac97_codec * codec)
+{
+ codec->codec_write(codec, AC97_POWER_CONTROL,
+ codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
+}
+
+
EXPORT_SYMBOL(ac97_read_proc);
EXPORT_SYMBOL(ac97_probe_codec);
temp1 = readl(s->pBA0+ BA0_PCICFG00);
temp2 = readl(s->pBA0+ BA0_PCICFG04);
temp1 = cs4281_hw_init(s);
- if(!temp1){
- printk(KERN_INFO "cs4281: Init4281() failed. Skipping part.\n");
+ if(temp1){
+ printk(KERN_INFO "cs4281: Hardware setup failed. Skipping part.\n");
continue;
}
s->magic = CS4281_MAGIC;
memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
dmabuf->endcleared = 1;
}
- }
- wake_up(&dmabuf->wait);
+ }
+ if (dmabuf->count < (signed)dmabuf->dmasize/2)
+ wake_up(&dmabuf->wait);
}
}
/* error handling and process wake up for DAC */
__stop_dac(state);
dmabuf->error++;
}
- wake_up(&dmabuf->wait);
+ if (dmabuf->count < (signed)dmabuf->dmasize/2)
+ wake_up(&dmabuf->wait);
}
}
}
static void amp_voyetra(struct cs_card *card, int change)
{
- /* Manage the EAPD bit on the Crystal 4297 */
+ /* Manage the EAPD bit on the Crystal 4297
+ and the Analog AD1885 */
+
int old=card->amplifier;
card->amplifier+=change;
void (*active)(struct cs_card *, int);
};
-static struct cs_card_type __init cards[]={
+static struct cs_card_type __initdata cards[]={
{0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL},
{0x5053, 0x3357, "Voyetra", amp_voyetra, NULL},
/* Not sure if the 570 needs the clkrun hack */
{PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack},
{PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack},
{PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL},
+ {0, 0, "Card without SSID set", NULL, NULL },
{0, 0, NULL, NULL}
};
static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u32 dacp, rp;
+ u32 dacp;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
if(rate < 8000)
rate = 8000;
+
+ if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE))
+ {
- /* Power down the DAC */
- dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
-
- /* Load the rate and read the effective rate */
- i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
- rp=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
-
- rate=(rp*48000) / clocking;
-
- /* Power it back up */
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
-
+ /* Power down the DAC */
+ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
+ /* Load the rate and read the effective rate */
+ i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
+ rate=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
+ /* Power it back up */
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+ }
+ rate=(rate*48000) / clocking;
dmabuf->rate = rate;
#ifdef DEBUG
printk("i810_audio: called i810_set_dac_rate : rate = %d\n", rate);
static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u32 dacp, rp;
+ u32 dacp;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
if(rate < 8000)
rate = 8000;
- /* Power down the ADC */
- dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
-
- /* Load the rate and read the effective rate */
- i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
- rp=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
-
-// printk("ADC rate set to %d Returned %d\n",
-// rate, (int)rp);
-
- rate = (rp * 48000) / clocking;
-
- /* Power it back up */
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
-
+ if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE))
+ {
+ /* Power down the ADC */
+ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
+ /* Load the rate and read the effective rate */
+ i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
+ rate=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
+ /* Power it back up */
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+ }
+ rate = (rate * 48000) / clocking;
dmabuf->rate = rate;
#ifdef DEBUG
printk("i810_audio: called i810_set_adc_rate : rate = %d\n", rate);
#endif
-
return rate;
}
memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
dmabuf->endcleared = 1;
}
- }
- wake_up(&dmabuf->wait);
+ }
+ if (dmabuf->count < (signed)dmabuf->dmasize/2) {
+ wake_up(&dmabuf->wait);
+ }
}
}
/* error handling and process wake up for DAC */
// printk("DMA overrun on send\n");
dmabuf->error++;
}
- wake_up(&dmabuf->wait);
+ if (dmabuf->count < (signed)dmabuf->dmasize/2) {
+ wake_up(&dmabuf->wait);
+ }
}
}
}
struct i810_card *card = dev->private_data;
int count = 1000;
- while(count-- && (inl(card->iobase + GLOB_STA) & 0x0100))
- udelay(10);
- if(!count)
- printk("i810_audio: AC97 access failed.\n");
- count=1000;
- while(count-- && (inb(card->iobase + CAS) & 1))
+ if (card->pci_id != INTEL440MX) {
+ while(--count && (inl(card->iobase + GLOB_STA) & 0x0100))
+ udelay(10);
+ if(!count)
+ printk("i810_audio: AC97 access failed.\n");
+ count=1000;
+ }
+ while(--count && (inb(card->iobase + CAS) & 1))
udelay(10);
if(!count)
printk("i810_audio: AC97 access failed.\n");
struct i810_card *card = dev->private_data;
int count = 1000;
- while(count-- && (inl(card->iobase + GLOB_STA) & 0x0100))
- udelay(10);
- if(!count)
- printk("i810_audio: AC97 write access failed.\n");
+ if (card->pci_id != INTEL440MX) {
+ while(--count && (inl(card->iobase + GLOB_STA) & 0x0100))
+ udelay(10);
+ if(!count)
+ printk("i810_audio: AC97 write access failed.\n");
- count=1000;
- while(count-- && (inb(card->iobase + CAS) & 1))
+ count=1000;
+ }
+ while(--count && (inb(card->iobase + CAS) & 1))
udelay(10);
if(!count)
printk("i810_audio: AC97 write access failed.\n");
printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");
return 0;
}
-
+
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ/5);
inw(card->ac97base);
-
+
for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
return -ENOMEM;
if (ac97_probe_codec(codec) == 0)
break;
+ /* Now check the codec for useful features to make up for
+ the dumbness of the 810 hardware engine */
+
eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
if(eid==0xFFFFFF)
break;
}
- /* Now check the codec for useful features to make up for
- the dumbness of the 810 hardware engine */
-
card->ac97_codec[num_ac97] = codec;
/* if there is no secondary codec at all, don't probe any more */
* Jaume Grau - flush caches on AARP_PROBE
* Rob Newberry - Added proxy AARP and AARP proc fs,
* moved probing from DDP module.
+ * Alistair Riddell- on AARP_PROBE flush sooner -
+ * ali@gwc.org.uk 000820
*
*/
getting into a probe/flush/learn/probe/flush/learn
cycle during probing of a slow to respond host addr */
if(a!=NULL)
+ {
a->expires_at=jiffies-1;
+ mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time);
+ }
}
if(sa.s_node!=ma->s_node)
break;
* port assignment. we lose a
* valid localtalk port as a
* result.
+ * Arnaldo Melo : fix minor skb handling bug
+ * in atalk_rcv
*
*
* This program is free software; you can redistribute it and/or
{
/* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
struct sk_buff *nskb = skb_realloc_headroom(skb, 32);
- kfree(skb);
+ kfree_skb(skb);
+ if (!nskb)
+ return 0;
skb=nskb;
}
else