patch-2.3.44 linux/drivers/scsi/aic7xxx.c
Next file: linux/drivers/scsi/aic7xxx_proc.c
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx.seq
Back to the patch index
Back to the overall index
- Lines: 1895
- Date:
Thu Feb 10 19:00:35 2000
- Orig file:
v2.3.43/linux/drivers/scsi/aic7xxx.c
- Orig date:
Wed Dec 8 14:11:26 1999
diff -u --recursive --new-file v2.3.43/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -264,7 +264,7 @@
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-#define AIC7XXX_C_VERSION "5.1.21"
+#define AIC7XXX_C_VERSION "5.2.0"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -823,6 +823,7 @@
* and what flags weren't. This way, I could clean up the flag usage on
* a use by use basis. Doug Ledford
*/
+ AHC_NO_STPWR = 0x00040000,
AHC_RESET_DELAY = 0x00080000,
AHC_A_SCANNED = 0x00100000,
AHC_B_SCANNED = 0x00200000,
@@ -883,6 +884,17 @@
AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3,
} ahc_feature;
+#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset)
+
+struct aic7xxx_scb_dma {
+ unsigned long dma_offset; /* Correction you have to add
+ * to virtual address to get
+ * dma handle in this region */
+ dma_addr_t dma_address; /* DMA handle of the start,
+ * for unmap */
+ unsigned int dma_len; /* DMA length */
+};
+
struct aic7xxx_scb {
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
@@ -891,15 +903,17 @@
struct hw_scatterlist *sg_list; /* SG list in adapter format */
unsigned char tag_action;
unsigned char sg_count;
- unsigned char sense_cmd[6]; /*
+ unsigned char *sense_cmd; /*
* Allocate 6 characters for
* sense command.
*/
+ unsigned char *cmnd;
unsigned int sg_length; /* We init this during buildscb so we
* don't have to calculate anything
* during underflow/overflow/stat code
*/
void *kmalloc_ptr;
+ struct aic7xxx_scb_dma *scb_dma;
};
/*
@@ -937,6 +951,8 @@
unsigned char numscbs; /* current number of scbs */
unsigned char maxhscbs; /* hardware scbs */
unsigned char maxscbs; /* max scbs including pageable scbs */
+ unsigned int hscbs_dma; /* DMA handle to hscbs */
+ unsigned int hscbs_dma_len; /* length of the above DMA area */
void *hscb_kmalloc_ptr;
} scb_data_type;
@@ -1014,6 +1030,9 @@
volatile unsigned char activescbs; /* active scbs */
volatile unsigned char max_activescbs;
volatile unsigned char qinfifonext;
+ volatile unsigned char *untagged_scbs;
+ volatile unsigned char *qoutfifo;
+ volatile unsigned char *qinfifo;
#define DEVICE_PRESENT 0x01
#define BUS_DEVICE_RESET_PENDING 0x02
@@ -1063,16 +1082,9 @@
* We put the less frequently used host structure items after the more
* frequently used items to try and ease the burden on the cache subsystem.
* These entries are not *commonly* accessed, whereas the preceding entries
- * are accessed very often. The only exceptions are the qinfifo, qoutfifo,
- * and untagged_scbs array. But, they are often accessed only once and each
- * access into these arrays is likely to blow a cache line, so they are put
- * down here so we can minimize the number of cache lines required to hold
- * the preceeding entries.
+ * are accessed very often.
*/
- volatile unsigned char untagged_scbs[256];
- volatile unsigned char qoutfifo[256];
- volatile unsigned char qinfifo[256];
unsigned int irq; /* IRQ for this adapter */
int instance; /* aic7xxx instance number */
int scsi_id; /* host adapter SCSI ID */
@@ -1085,9 +1097,7 @@
unsigned short ultraenb; /* Ultra mode target list */
unsigned short bios_control; /* bios control - SEEPROM */
unsigned short adapter_control; /* adapter control - SEEPROM */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- struct pci_dev *pdev;
-#endif
+ struct pci_dev *pdev;
unsigned char pci_bus;
unsigned char pci_device_fn;
struct seeprom_config sc;
@@ -1098,6 +1108,7 @@
int host_no; /* SCSI host number */
unsigned long mbase; /* I/O memory address */
ahc_chip chip; /* chip type */
+ dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
/*
* Statistics Kept:
@@ -1354,10 +1365,10 @@
/*
* So that we can set how long each device is given as a selection timeout.
* The table of values goes like this:
- * 0 - 256ms
- * 1 - 128ms
- * 2 - 64ms
- * 3 - 32ms
+ * 0 - 256ms
+ * 1 - 128ms
+ * 2 - 64ms
+ * 3 - 32ms
* We default to 64ms because it's fast. Some old SCSI-I devices need a
* longer time. The final value has to be left shifted by 3, hence 0x10
* is the final value.
@@ -1467,6 +1478,7 @@
{
x = inb(p->base + port);
}
+ mb();
return(x);
#else
return(inb(p->base + port));
@@ -1770,6 +1782,7 @@
struct ins_format1 *fmt1_ins;
struct ins_format3 *fmt3_ins;
unsigned char opcode;
+ volatile unsigned char hcntrl;
instr = *(union ins_formats*) &seqprog[instrptr * 4];
@@ -1871,12 +1884,13 @@
}
}
aic_outb(p, (instr.integer & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+ hcntrl = aic_inb(p, HCNTRL);
udelay(50);
break;
@@ -1991,21 +2005,6 @@
/*+F*************************************************************************
* Function:
- * aic7xxx_delay
- *
- * Description:
- * Delay for specified amount of time. We use mdelay because the timer
- * interrupt is not guaranteed to be enabled. This will cause an
- * infinite loop since jiffies (clock ticks) is not updated.
- *-F*************************************************************************/
-static void
-aic7xxx_delay(int seconds)
-{
- mdelay(seconds * 1000);
-}
-
-/*+F*************************************************************************
- * Function:
* aic7xxx_info
*
* Description:
@@ -2728,15 +2727,14 @@
aic7xxx_allocate_scb(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scbp = NULL;
- int scb_size = sizeof(struct aic7xxx_scb) +
- sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+ int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6;
int i;
int step = PAGE_SIZE / 1024;
unsigned long scb_count = 0;
struct hw_scatterlist *hsgp;
struct aic7xxx_scb *scb_ap;
- unsigned long temp;
-
+ struct aic7xxx_scb_dma *scb_dma;
+ unsigned char *bufs;
if (p->scb_data->numscbs < p->scb_data->maxscbs)
{
@@ -2750,6 +2748,11 @@
* efficiency since scb_size * (i -1) is growing slightly faster
* than the right hand side. If the number of SG array elements
* is changed, this function may not be near so efficient any more.
+ *
+ * Since the DMA'able buffers are now allocated in a seperate
+ * chunk this algorithm has been modified to match. The '12'
+ * and '6' factors in scb_size are for the DMA'able command byte
+ * and sensebuffers respectively. -DaveM
*/
for ( i=step;; i *= 2 )
{
@@ -2760,44 +2763,53 @@
}
}
scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs);
- scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
- if (scb_ap != NULL)
+ scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count
+ + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC);
+ if (scb_ap == NULL)
+ return(0);
+ scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count];
+ hsgp = (struct hw_scatterlist *)
+ pci_alloc_consistent(p->pdev, scb_size * scb_count,
+ &scb_dma->dma_address);
+ if (hsgp == NULL)
{
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- {
- if (p->scb_data->numscbs == 0)
- printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
- p->host_no, -1, -1, -1, scb_count);
- else
- printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
- p->host_no, -1, -1, -1, scb_count);
- }
-#endif
- memset(scb_ap, 0, scb_count * scb_size);
- temp = (unsigned long) &scb_ap[scb_count];
- temp += 1023;
- temp &= ~1023;
- hsgp = (struct hw_scatterlist *)temp;
- for (i=0; i < scb_count; i++)
- {
- scbp = &scb_ap[i];
- scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
- scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
- memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
- scbp->hscb->tag = p->scb_data->numscbs;
- /*
- * Place in the scb array; never is removed
- */
- p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
- scbq_insert_tail(&p->scb_data->free_scbs, scbp);
- }
- scbp->kmalloc_ptr = scb_ap;
+ kfree(scb_ap);
+ return(0);
}
- else
+ bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG];
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+ if (aic7xxx_verbose > 0xffff)
{
- return(0);
+ if (p->scb_data->numscbs == 0)
+ printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ else
+ printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ }
+#endif
+ memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count);
+ scb_dma->dma_offset = (unsigned long)scb_dma->dma_address
+ - (unsigned long)hsgp;
+ scb_dma->dma_len = scb_size * scb_count;
+ for (i=0; i < scb_count; i++)
+ {
+ scbp = &scb_ap[i];
+ scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+ scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+ scbp->sense_cmd = bufs;
+ scbp->cmnd = bufs + 6;
+ bufs += 12 + 6;
+ scbp->scb_dma = scb_dma;
+ memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+ scbp->hscb->tag = p->scb_data->numscbs;
+ /*
+ * Place in the scb array; never is removed
+ */
+ p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+ scbq_insert_tail(&p->scb_data->free_scbs, scbp);
}
+ scbp->kmalloc_ptr = scb_ap;
}
return(scb_count);
}
@@ -2882,6 +2894,16 @@
struct aic7xxx_scb *scbp;
unsigned char queue_depth;
+ if (scb->sg_count == 1)
+ pci_unmap_single(p->pdev, le32_to_cpu(scb->sg_list[0].address),
+ le32_to_cpu(scb->sg_list[0].length));
+ else if (scb->sg_count > 1)
+ {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ pci_unmap_sg(p->pdev, sg, cmd->use_sg);
+ }
if (scb->flags & SCB_RECOVERY_SCB)
{
p->flags &= ~AHC_ABORT_PENDING;
@@ -3889,11 +3911,19 @@
while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0)
mdelay(5);
- mdelay(10);
+ /*
+ * Some of the new Ultra2 chipsets need a longer delay after a chip
+ * reset than just the init setup creates, so we have to delay here
+ * before we go into a reset in order to make the chips happy.
+ */
+ if (p->features & AHC_ULTRA2)
+ mdelay(250);
+ else
+ mdelay(50);
/* Turn off the bus reset. */
aic_outb(p, 0, SCSISEQ);
- mdelay(5);
+ mdelay(10);
aic7xxx_clear_intstat(p);
/* Re-enable reset interrupts. */
@@ -4772,6 +4802,7 @@
case CHECK_CONDITION:
if ( !(scb->flags & SCB_SENSE) )
{
+ unsigned char *sense_buffer;
/*
* XXX - How do we save the residual (if there is one).
*/
@@ -4782,14 +4813,13 @@
* Send a sense command to the requesting target.
* XXX - revisit this and get rid of the memcopys.
*/
- memcpy(&scb->sense_cmd[0], &generic_sense[0],
+ memcpy(scb->sense_cmd, &generic_sense[0],
sizeof(generic_sense));
scb->sense_cmd[1] = (cmd->lun << 5);
scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
- scb->sg_list[0].address =
- cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+ sense_buffer = cmd->sense_buffer;
scb->sg_list[0].length =
cpu_to_le32(sizeof(cmd->sense_buffer));
@@ -4801,11 +4831,10 @@
hscb->control = 0;
hscb->target_status = 0;
hscb->SG_list_pointer =
- cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
- hscb->data_pointer = scb->sg_list[0].address;
+ cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list));
hscb->data_count = scb->sg_list[0].length;
hscb->SCSI_cmd_pointer =
- cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+ cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd));
hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
hscb->residual_SG_segment_count = 0;
hscb->residual_data_count[0] = 0;
@@ -4854,12 +4883,13 @@
* SENSE information anyway.
*/
if (cmd->next->cmnd[0] != TEST_UNIT_READY)
- {
- scb->sg_list[0].address =
- cpu_to_le32(VIRT_TO_BUS(&cmd->next->sense_buffer[0]));
- hscb->data_pointer = scb->sg_list[0].address;
- }
+ sense_buffer = cmd->next->sense_buffer;
}
+ scb->sg_list[0].address =
+ cpu_to_le32(pci_map_single(p->pdev, sense_buffer,
+ sizeof(cmd->sense_buffer)));
+ hscb->data_pointer = scb->sg_list[0].address;
+
scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
@@ -5134,7 +5164,7 @@
else if (scb->flags & SCB_MSGOUT_PPR)
{
unsigned int max_sync, period;
- unsigned char options = p->transinfo[tindex].goal_options;
+ unsigned char options = 0;
if (p->features & AHC_ULTRA2)
{
@@ -5145,9 +5175,10 @@
(p->dev_flags[tindex] & DEVICE_SCSI_3) &&
(p->transinfo[tindex].goal_width ==
MSG_EXT_WDTR_BUS_16_BIT) &&
- (options != 0) )
+ (p->transinfo[tindex].goal_options != 0) )
{
max_sync = AHC_SYNCRATE_ULTRA3;
+ options = p->transinfo[tindex].goal_options;
}
else
{
@@ -5296,6 +5327,188 @@
}
break;
+ case WIDE_RESIDUE:
+ {
+ unsigned char resid_sgcnt, index;
+ unsigned char scb_index = aic_inb(p, SCB_TAG);
+ unsigned int cur_addr, resid_dcnt;
+ unsigned int native_addr, native_length;
+ int i;
+
+ if(scb_index > p->scb_data->numscbs)
+ {
+ printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n",
+ p->host_no, -1, -1, -1);
+ /*
+ * XXX: Add error handling here
+ */
+ break;
+ }
+ scb = p->scb_data->scb_array[scb_index];
+ if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x "
+ "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb),
+ scb->flags, (unsigned long)scb->cmd);
+ break;
+ }
+
+ /*
+ * We have a valid scb to use on this WIDE_RESIDUE message, so
+ * we need to walk the sg list looking for this particular sg
+ * segment, then see if we happen to be at the very beginning of
+ * the segment. If we are, then we have to back things up to
+ * the previous segment. If not, then we simply need to remove
+ * one byte from this segments address and add one to the byte
+ * count.
+ */
+ cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
+ (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+ resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
+ resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
+ (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
+ (aic_inb(p, SCB_RESID_DCNT + 2) << 24);
+ index = scb->sg_count - resid_sgcnt;
+ native_addr = le32_to_cpu(scb->sg_list[index].address);
+ native_length = le32_to_cpu(scb->sg_list[index].length);
+ /*
+ * Make sure this is a valid sg_seg for the given pointer
+ */
+ if(cur_addr < native_addr ||
+ cur_addr > (native_addr + native_length))
+ {
+ printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
+ p->host_no, CTL_OF_SCB(scb), cur_addr);
+ if(index > 0)
+ printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ le32_to_cpu(scb->sg_list[index - 1].address),
+ le32_to_cpu(scb->sg_list[index - 1].length));
+ printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ native_addr, native_length);
+ if(resid_sgcnt > 1)
+ printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ le32_to_cpu(scb->sg_list[index + 1].address),
+ le32_to_cpu(scb->sg_list[index + 1].length));
+ break;
+ }
+
+ /*
+ * If our current address matches the sg_seg->address then we
+ * have to back up the sg array to the previous segment and set
+ * it up to have only one byte of transfer left to go.
+ */
+ if(cur_addr == native_addr)
+ {
+ if(index == 0)
+ {
+ printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
+ "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+ break;
+ }
+ resid_sgcnt++;
+ index--;
+ cur_addr = le32_to_cpu(scb->sg_list[index].address) +
+ le32_to_cpu(scb->sg_list[index].length) - 1;
+ native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
+ | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
+ native_addr -= SG_SIZEOF;
+ aic_outb(p, resid_sgcnt, SG_COUNT);
+ aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+ aic_outb(p, native_addr & 0xff, SG_NEXT);
+ aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
+ aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
+ aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
+ aic_outb(p, 1, SCB_RESID_DCNT);
+ aic_outb(p, 0, SCB_RESID_DCNT + 1);
+ aic_outb(p, 0, SCB_RESID_DCNT + 2);
+ aic_outb(p, 1, HCNT);
+ aic_outb(p, 0, HCNT + 1);
+ aic_outb(p, 0, HCNT + 2);
+ aic_outb(p, cur_addr & 0xff, HADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ /*
+ * The sequencer actually wants to find the new address and byte
+ * count in the SHCNT and SHADDR register sets. These registers
+ * are a shadow of the regular HCNT and HADDR registers. On the
+ * Ultra2 controllers, these registers are read only and the way
+ * we have to set their values is to put the values we want into
+ * the HCNT and HADDR registers and then output PRELOADEN into
+ * the DFCNTRL register which causes the card to latch the current
+ * values in the HADDR and HCNT registers and drop it through to
+ * the shadow registers. On older cards we copy them directly
+ * across by hand.
+ */
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ udelay(1);
+ }
+ }
+ else
+ {
+ aic_outb(p, 1, STCNT);
+ aic_outb(p, 0, STCNT + 1);
+ aic_outb(p, 0, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
+ }
+ else
+ {
+ /*
+ * Back the data pointer up by one and add one to the remaining
+ * byte count. Then store that in the HCNT and HADDR registers.
+ */
+ cur_addr--;
+ resid_dcnt++;
+ aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+ aic_outb(p, resid_dcnt & 0xff, HCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+ aic_outb(p, cur_addr & 0xff, HADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ udelay(1);
+ }
+ }
+ else
+ {
+ aic_outb(p, resid_dcnt & 0xff, STCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
+ }
+ }
+ break;
+
+
#if AIC7XXX_NOT_YET
case TRACEPOINT:
{
@@ -5655,16 +5868,6 @@
break;
}
- /*
- * If we aren't on one of the new Ultra3 cards, then reject any PPR
- * message since we can't support any option field other than 0
- */
- if( !(p->features & AHC_ULTRA3) )
- {
- reject = TRUE;
- break;
- }
-
if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
{
break;
@@ -6810,7 +7013,7 @@
return;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
spin_lock_irqsave(&io_request_lock, cpu_flags);
- if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags))
+ if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
{
return;
}
@@ -6820,7 +7023,7 @@
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
- clear_bit(AHC_IN_ISR_BIT, &p->flags);
+ clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
#else
if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
@@ -7212,6 +7415,21 @@
#undef CLOCK_PULSE
}
+#define CLOCK_PULSE(p) \
+ do { \
+ int limit = 0; \
+ do { \
+ mb(); \
+ pause_sequencer(p); /* This is just to generate some PCI */ \
+ /* traffic so the PCI read is flushed */ \
+ /* it shouldn't be needed, but some */ \
+ /* chipsets do indeed appear to need */ \
+ /* something to force PCI reads to get */ \
+ /* flushed */ \
+ udelay(1); /* Do nothing */ \
+ } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \
+ } while(0)
+
/*+F*************************************************************************
* Function:
* acquire_seeprom
@@ -7222,7 +7440,6 @@
static int
acquire_seeprom(struct aic7xxx_host *p)
{
- int wait;
/*
* Request access of the memory port. When access is
@@ -7232,12 +7449,7 @@
* should be no contention.
*/
aic_outb(p, SEEMS, SEECTL);
- wait = 1000; /* 1000 msec = 1 second */
- while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
- {
- wait--;
- mdelay(1); /* 1 msec */
- }
+ CLOCK_PULSE(p);
if ((aic_inb(p, SEECTL) & SEERDY) == 0)
{
aic_outb(p, 0, SEECTL);
@@ -7256,7 +7468,12 @@
static void
release_seeprom(struct aic7xxx_host *p)
{
+ /*
+ * Make sure the SEEPROM is ready before we release it.
+ */
+ CLOCK_PULSE(p);
aic_outb(p, 0, SEECTL);
+ CLOCK_PULSE(p);
}
/*+F*************************************************************************
@@ -7322,12 +7539,6 @@
};
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
-#define CLOCK_PULSE(p) \
- while ((aic_inb(p, SEECTL) & SEERDY) == 0) \
- { \
- ; /* Do nothing */ \
- }
-
/*
* Request access of the memory port.
*/
@@ -7443,7 +7654,6 @@
}
return (1);
-#undef CLOCK_PULSE
}
/*+F*************************************************************************
@@ -7458,12 +7668,18 @@
{
unsigned char brdctl, value;
+ /*
+ * Make sure the SEEPROM is ready before we access it
+ */
+ CLOCK_PULSE(p);
if (p->features & AHC_ULTRA2)
{
brdctl = BRDRW_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
- return(aic_inb(p, BRDCTL));
+ CLOCK_PULSE(p);
+ value = aic_inb(p, BRDCTL);
+ CLOCK_PULSE(p);
+ return(value);
}
brdctl = BRDRW;
if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
@@ -7472,10 +7688,11 @@
brdctl |= BRDCS;
}
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
value = aic_inb(p, BRDCTL);
+ CLOCK_PULSE(p);
aic_outb(p, 0, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
return (value);
}
@@ -7491,18 +7708,23 @@
{
unsigned char brdctl;
+ /*
+ * Make sure the SEEPROM is ready before we access it
+ */
+ CLOCK_PULSE(p);
if (p->features & AHC_ULTRA2)
{
brdctl = value;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
brdctl |= BRDSTB_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
brdctl &= ~BRDSTB_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
read_brdctl(p);
+ CLOCK_PULSE(p);
}
else
{
@@ -7514,19 +7736,21 @@
}
brdctl = BRDSTB | BRDCS;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl |= value;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl &= ~BRDSTB;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl &= ~BRDCS;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
}
}
+#undef CLOCK_PULSE
+
/*+F*************************************************************************
* Function:
* aic785x_cable_detect
@@ -7903,12 +8127,6 @@
unsigned char term, scsi_conf;
struct Scsi_Host *host;
- /*
- * Lock out other contenders for our i/o space.
- */
- request_region(p->base, MAXREG - MINREG, "aic7xxx");
-
-
host = p->host;
p->scb_data->maxscbs = AIC7XXX_MAXSCB;
@@ -7944,12 +8162,6 @@
p->dev_timer.function = (void *)aic7xxx_timer;
p->dev_timer_active = 0;
- for (i = 0; i < NUMBER(p->untagged_scbs); i++)
- {
- p->untagged_scbs[i] = SCB_LIST_NULL;
- p->qinfifo[i] = SCB_LIST_NULL;
- p->qoutfifo[i] = SCB_LIST_NULL;
- }
/*
* We currently have no commands of any type
*/
@@ -7980,7 +8192,7 @@
printk("VLB slot %d\n", p->pci_device_fn);
break;
default:
- printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+ printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
PCI_FUNC(p->pci_device_fn));
break;
}
@@ -8016,6 +8228,20 @@
}
aic_outb(p, 0, SEQ_FLAGS);
+ /*
+ * We are starting to do real work on the card....it's possible we could
+ * generate some spurious interrupts at this point, especially in the
+ * event of a PCI error or some such. If there are other devices already
+ * registered on the same interrupt as us, this could cause the machine
+ * to lock up. So, we disable the interrupt this card is on until we
+ * finish our card setup. We only need to do this for modules, if we are
+ * compiled into the kernel then interrupts are already off during this
+ * part of the code.
+ */
+#ifdef MODULE
+ disable_irq(p->irq);
+#endif
+
detect_maxscb(p);
@@ -8051,15 +8277,15 @@
#endif
if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
{
- devconfig |= 0x02;
+ devconfig |= STPWLEVEL;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force setting STPWLEV bit\n", p->host_no);
+ printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no);
}
else
{
- devconfig &= ~0x02;
+ devconfig &= ~STPWLEVEL;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force clearing STPWLEV bit\n", p->host_no);
+ printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no);
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
@@ -8121,11 +8347,6 @@
}
/*
- * Clear out any possible pending interrupts.
- */
- aic7xxx_clear_intstat(p);
-
- /*
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->features & AHC_TWIN)
@@ -8168,7 +8389,17 @@
aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term |
ENSTIMER | ACTNEGEN, SXFRCTL1);
aic_outb(p, 0, SIMODE0);
- aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+ /*
+ * If we are a cardbus adapter then don't enable SCSI reset detection.
+ * We shouldn't likely be sharing SCSI busses with someone else, and
+ * if we don't have a cable currently plugged into the controller then
+ * we won't have a power source for the SCSI termination, which means
+ * we'll see infinite incoming bus resets.
+ */
+ if(p->flags & AHC_NO_STPWR)
+ aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1);
+ else
+ aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
aic_outb(p, 0, SCSIRATE);
if ( p->features & AHC_ULTRA2)
aic_outb(p, 0, SCSIOFFSET);
@@ -8227,44 +8458,57 @@
{
size_t array_size;
unsigned int hscb_physaddr;
- unsigned long temp;
array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
if (p->scb_data->hscbs == NULL)
{
- /*
- * A little padding so we can align thing the way we want
+ /* pci_alloc_consistent enforces the alignment already and
+ * clears the area as well.
*/
- p->scb_data->hscbs = kmalloc(array_size + 0x1f, GFP_ATOMIC);
+ p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size,
+ &p->scb_data->hscbs_dma);
+ /* We have to use pci_free_consistent, not kfree */
+ p->scb_data->hscb_kmalloc_ptr = NULL;
+ p->scb_data->hscbs_dma_len = array_size;
}
if (p->scb_data->hscbs == NULL)
{
printk("(scsi%d) Unable to allocate hardware SCB array; "
"failing detection.\n", p->host_no);
+ aic_outb(p, 0, SIMODE1);
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
p->irq = 0;
return(0);
}
- /*
- * Save the actual kmalloc buffer pointer off, then align our
- * buffer to a 32 byte boundary
- */
- p->scb_data->hscb_kmalloc_ptr = p->scb_data->hscbs;
- temp = (unsigned long)p->scb_data->hscbs;
- temp += 0x1f;
- temp &= ~0x1f;
- p->scb_data->hscbs = (struct aic7xxx_hwscb *)temp;
- /* At least the control byte of each SCB needs to be 0. */
- memset(p->scb_data->hscbs, 0, array_size);
- /* Tell the sequencer where it can find the hardware SCB array. */
- hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
+ hscb_physaddr = p->scb_data->hscbs_dma;
aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
/* Set up the fifo areas at the same time */
- hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+ p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma);
+ if (p->untagged_scbs == NULL)
+ {
+ printk("(scsi%d) Unable to allocate hardware FIFO arrays; "
+ "failing detection.\n", p->host_no);
+ p->irq = 0;
+ return(0);
+ }
+
+ p->qoutfifo = p->untagged_scbs + 256;
+ p->qinfifo = p->qoutfifo + 256;
+ for (i = 0; i < 256; i++)
+ {
+ p->untagged_scbs[i] = SCB_LIST_NULL;
+ p->qinfifo[i] = SCB_LIST_NULL;
+ p->qoutfifo[i] = SCB_LIST_NULL;
+ }
+
+ hscb_physaddr = p->fifo_dma;
aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
@@ -8315,11 +8559,6 @@
first_aic7xxx = p;
/*
- * Clear out any possible pending interrupts, again.
- */
- aic7xxx_clear_intstat(p);
-
- /*
* Allocate the first set of scbs for this controller. This is to stream-
* line code elsewhere in the driver. If we have to check for the existence
* of scbs in certain code sections, it slows things down. However, as
@@ -8373,20 +8612,21 @@
printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
}
- /*
- * Some of the new Ultra2 chipsets need a longer delay after a chip
- * reset than just the init setup creates, so we have to delay here
- * before we go into a reset in order to make the chips happy.
- */
- if (p->features & AHC_ULTRA2)
- mdelay(250);
aic7xxx_reset_current_bus(p);
/*
- * Delay for the reset delay.
+ * Delay for the reset delay by setting the timer, this will delay
+ * future commands sent to any devices.
*/
- if (!reset_delay)
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ p->flags |= AHC_RESET_DELAY;
+ for(i=0; i<MAX_TARGETS; i++)
+ {
+ p->dev_expires[i] = jiffies + (4 * HZ);
+ p->dev_timer_active |= (0x01 << i);
+ }
+ p->dev_timer.expires = p->dev_expires[p->scsi_id];
+ add_timer(&p->dev_timer);
+ p->dev_timer_active |= (0x01 << MAX_TARGETS);
}
else
{
@@ -8396,11 +8636,6 @@
"the no_reset\n", p->host_no);
printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
"for it.\n", p->host_no);
- printk(KERN_INFO "(scsi%d) The no_reset option is known to break some "
- "systems,\n", p->host_no);
- printk(KERN_INFO "(scsi%d) and is not supported by the driver author\n",
- p->host_no);
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
}
}
@@ -8426,10 +8661,23 @@
{
printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
"controller.\n", p->host_no, p->irq);
+ aic_outb(p, 0, SIMODE1);
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
p->irq = 0;
return (0);
}
+ if(aic_inb(p, INTSTAT) & INT_PEND)
+ printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n",
+ p->host_no, -1, -1 , -1);
+ aic7xxx_clear_intstat(p);
+
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
+
unpause_sequencer(p, /* unpause_always */ TRUE);
return (found);
@@ -8462,7 +8710,7 @@
wait = 1000; /* 1 second (1000 * 1 msec) */
while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
{
- mdelay(1); /* 1 msec */
+ udelay(1); /* 1 msec */
}
pause_sequencer(p);
@@ -8566,9 +8814,11 @@
*/
if (p->scb_data != NULL)
{
+ struct aic7xxx_scb_dma *scb_dma = NULL;
if (p->scb_data->hscbs != NULL)
{
- kfree(p->scb_data->hscb_kmalloc_ptr);
+ pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len,
+ p->scb_data->hscbs, p->scb_data->hscbs_dma);
p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL;
}
/*
@@ -8579,6 +8829,14 @@
*/
for (i = 0; i < p->scb_data->numscbs; i++)
{
+ if (p->scb_data->scb_array[i]->scb_dma != scb_dma)
+ {
+ scb_dma = p->scb_data->scb_array[i]->scb_dma;
+ pci_free_consistent(p->pdev, scb_dma->dma_len,
+ (void *)((unsigned long)scb_dma->dma_address
+ - scb_dma->dma_offset),
+ scb_dma->dma_address);
+ }
if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
p->scb_data->scb_array[i] = NULL;
@@ -8606,6 +8864,7 @@
}
}
+ pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
}
/*+F*************************************************************************
@@ -8657,15 +8916,15 @@
if (!have_seeprom)
{
p->sc_size = 128;
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, p->sc_type);
if (!have_seeprom)
{
if(p->sc_type == C46)
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, C56_66);
else
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, C46);
}
}
@@ -9098,271 +9357,17 @@
template->sg_tablesize = AIC7XXX_MAX_SG;
-#if defined(__i386__) || defined(__alpha__)
#ifdef CONFIG_PCI
/*
- * PCI-bus chipset probe.
+ * PCI-bus probe.
*/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
if (pci_present())
- {
- if (pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82450GX,
- NULL))
- aic7xxx_no_probe = 1;
- if (pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82451NX,
- NULL))
- aic7xxx_no_probe = 1;
- }
#else
-#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
if (pcibios_present())
+#endif
{
- unsigned char pci_bus, pci_devfn;
- if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82450GX,
- 0, &pci_bus, &pci_devfn)) )
- aic7xxx_no_probe = 1;
- if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82451NX,
- 0, &pci_bus, &pci_devfn)) )
- aic7xxx_no_probe = 1;
- }
-#endif /* LINUX_VERSION_CODE */
-#endif /* CONFIG_PCI */
- /*
- * EISA/VL-bus card signature probe.
- */
- slot = MINSLOT;
- while ( (slot <= MAXSLOT) &&
- !(aic7xxx_no_probe) )
- {
- base = SLOTBASE(slot) + MINREG;
-
- if (check_region(base, MAXREG - MINREG))
- {
- /*
- * Some other driver has staked a
- * claim to this i/o region already.
- */
- slot++;
- continue; /* back to the beginning of the for loop */
- }
- flags = 0;
- type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
- if (type == -1)
- {
- slot++;
- continue;
- }
- temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
- if (temp_p == NULL)
- {
- printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
- slot++;
- continue; /* back to the beginning of the while loop */
- }
- /*
- * Pause the card preserving the IRQ type. Allow the operator
- * to override the IRQ trigger.
- */
- if (aic7xxx_irq_trigger == 1)
- hcntrl = IRQMS; /* Level */
- else if (aic7xxx_irq_trigger == 0)
- hcntrl = 0; /* Edge */
- else
- hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
- memset(temp_p, 0, sizeof(struct aic7xxx_host));
- temp_p->unpause = hcntrl | INTEN;
- temp_p->pause = hcntrl | PAUSE | INTEN;
- temp_p->base = base;
- temp_p->mbase = 0;
- temp_p->maddr = 0;
- temp_p->pci_bus = 0;
- temp_p->pci_device_fn = slot;
- aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
- while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
- if (aic7xxx_chip_reset(temp_p) == -1)
- temp_p->irq = 0;
- else
- temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
- temp_p->flags |= AHC_PAGESCBS;
-
- switch (temp_p->irq)
- {
- case 9:
- case 10:
- case 11:
- case 12:
- case 14:
- case 15:
- break;
-
- default:
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
- "level %d, ignoring.\n", temp_p->irq);
- kfree(temp_p);
- slot++;
- continue; /* back to the beginning of the while loop */
- }
-
- /*
- * We are commited now, everything has been checked and this card
- * has been found, now we just set it up
- */
-
- /*
- * Insert our new struct into the list at the end
- */
- if (list_p == NULL)
- {
- list_p = current_p = temp_p;
- }
- else
- {
- current_p = list_p;
- while (current_p->next != NULL)
- current_p = current_p->next;
- current_p->next = temp_p;
- }
-
- switch (type)
- {
- case 0:
- temp_p->board_name_index = 2;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %d\n",
- board_names[2], slot);
- /* FALLTHROUGH */
- case 1:
- {
- temp_p->chip = AHC_AIC7770 | AHC_EISA;
- temp_p->features |= AHC_AIC7770_FE;
- temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
-
- /*
- * Get the primary channel information. Right now we don't
- * do anything with this, but someday we will be able to inform
- * the mid-level SCSI code which channel is primary.
- */
- if (temp_p->board_name_index == 0)
- {
- temp_p->board_name_index = 3;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %d\n",
- board_names[3], slot);
- }
- if (temp_p->bios_control & CHANNEL_B_PRIMARY)
- {
- temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
- }
-
- if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
- {
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- }
- else
- {
- temp_p->flags &= ~AHC_USEDEFAULTS;
- temp_p->flags |= AHC_BIOS_ENABLED;
- if ( (temp_p->bios_control & 0x20) == 0 )
- {
- temp_p->bios_address = 0xcc000;
- temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
- }
- else
- {
- temp_p->bios_address = 0xd0000;
- temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
- }
- }
- temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
- temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
- if (temp_p->features & AHC_WIDE)
- {
- temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
- temp_p->scsi_id_b = temp_p->scsi_id;
- }
- else
- {
- temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
- temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
- }
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- }
-
- case 2:
- case 3:
- temp_p->chip = AHC_AIC7770 | AHC_VL;
- temp_p->features |= AHC_AIC7770_FE;
- if (type == 2)
- temp_p->flags |= AHC_BIOS_ENABLED;
- else
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
- sxfrctl1 = STPWEN;
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- temp_p->board_name_index = 4;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at VLB %d\n",
- board_names[2], slot);
- switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
- {
- case 0x00:
- temp_p->bios_address = 0xe0000;
- break;
- case 0x20:
- temp_p->bios_address = 0xc8000;
- break;
- case 0x40:
- temp_p->bios_address = 0xd0000;
- break;
- case 0x60:
- temp_p->bios_address = 0xd8000;
- break;
- default:
- break; /* can't get here */
- }
- break;
-
- default: /* Won't get here. */
- break;
- }
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
- (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
- temp_p->irq,
- (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
- }
-
- /*
- * Set the FIFO threshold and the bus off time.
- */
- hostconf = aic_inb(temp_p, HOSTCONF);
- aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
- aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
- slot++;
- found++;
- }
-
-#endif /* defined(__i386__) || defined(__alpha__) */
-
-#ifdef CONFIG_PCI
- /*
- * PCI-bus probe.
- */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- if (pci_present())
-#else
- if (pcibios_present())
-#endif
- {
- struct
+ struct
{
unsigned short vendor_id;
unsigned short device_id;
@@ -9485,7 +9490,7 @@
AHC_AIC7896_FE, 25,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWR,
AHC_AIC7860_FE, 26,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
@@ -9594,8 +9599,8 @@
if (aic7xxx_verbose & VERBOSE_PROBE2)
printk("aic7xxx: <%s> at PCI %d/%d\n",
board_names[aic_pdevs[i].board_name_index],
- PCI_SLOT(temp_p->pdev->devfn),
- PCI_FUNC(temp_p->pdev->devfn));
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
pci_read_config_word(pdev, PCI_COMMAND, &command);
if (aic7xxx_verbose & VERBOSE_PROBE2)
{
@@ -9651,8 +9656,9 @@
if ( temp_p == NULL )
continue;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at PCI %d/%d\n",
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
@@ -9682,14 +9688,28 @@
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
+ if(check_region(temp_p->base, MAXREG - MINREG))
+ {
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: I/O ports already in use, ignoring.\n");
+ kfree(temp_p);
+ temp_p = NULL;
+ continue;
+ }
+
temp_p->unpause = INTEN;
temp_p->pause = temp_p->unpause | PAUSE;
if ( ((temp_p->base == 0) &&
(temp_p->mbase == 0)) ||
(temp_p->irq == 0) )
{
- printk("aic7xxx: <%s> at PCI %d/%d\n",
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
@@ -9724,8 +9744,9 @@
/*
* OK.....we failed our test....go back to programmed I/O
*/
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
@@ -9742,6 +9763,11 @@
#endif
/*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
+
+ /*
* We HAVE to make sure the first pause_sequencer() and all other
* subsequent I/O that isn't PCI config space I/O takes place
* after the MMAPed I/O region is configured and tested. The
@@ -9773,14 +9799,31 @@
/*
* Get current termination setting
*/
- sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+ sxfrctl1 = aic_inb(temp_p, SXFRCTL1);
if (aic7xxx_chip_reset(temp_p) == -1)
{
+ release_region(temp_p->base, MAXREG - MINREG);
kfree(temp_p);
temp_p = NULL;
continue;
}
+ /*
+ * Very quickly put the term setting back into the register since
+ * the chip reset may cause odd things to happen. This is to keep
+ * LVD busses with lots of drives from draining the power out of
+ * the diffsense line before we get around to running the
+ * configure_termination() function. Also restore the STPWLEVEL
+ * bit of DEVCONFIG
+ */
+ aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+ pcibios_write_config_dword(temp_p->pci_bus, temp_p->pci_device_fn,
+ DEVCONFIG, devconfig);
+#else
+ pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
+#endif
+ sxfrctl1 &= STPWEN;
/*
* We need to set the CHNL? assignments before loading the SEEPROM
@@ -9815,7 +9858,7 @@
case AHC_AIC7896: /* 7896/7 */
case AHC_AIC7899: /* 7899 */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- if (PCI_FUNC(temp_p->pdev->devfn) != 0)
+ if (PCI_FUNC(pdev->devfn) != 0)
{
temp_p->flags |= AHC_CHNLB;
}
@@ -10007,8 +10050,9 @@
}
else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
{
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: external SCB RAM detected, "
@@ -10025,8 +10069,9 @@
}
else if (devconfig & RAMPSM)
{
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: external SCB RAM detected, "
@@ -10091,6 +10136,235 @@
} /* for PCI_DEVICES */
} /* PCI BIOS present */
#endif CONFIG_PCI
+
+#if defined(__i386__) || defined(__alpha__)
+ /*
+ * EISA/VL-bus card signature probe.
+ */
+ slot = MINSLOT;
+ while ( (slot <= MAXSLOT) &&
+ !(aic7xxx_no_probe) )
+ {
+ base = SLOTBASE(slot) + MINREG;
+
+ if (check_region(base, MAXREG - MINREG))
+ {
+ /*
+ * Some other driver has staked a
+ * claim to this i/o region already.
+ */
+ slot++;
+ continue; /* back to the beginning of the for loop */
+ }
+ flags = 0;
+ type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
+ if (type == -1)
+ {
+ slot++;
+ continue;
+ }
+ temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+ if (temp_p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+ /*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(base, MAXREG - MINREG, "aic7xxx");
+
+ /*
+ * Pause the card preserving the IRQ type. Allow the operator
+ * to override the IRQ trigger.
+ */
+ if (aic7xxx_irq_trigger == 1)
+ hcntrl = IRQMS; /* Level */
+ else if (aic7xxx_irq_trigger == 0)
+ hcntrl = 0; /* Edge */
+ else
+ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
+ memset(temp_p, 0, sizeof(struct aic7xxx_host));
+ temp_p->unpause = hcntrl | INTEN;
+ temp_p->pause = hcntrl | PAUSE | INTEN;
+ temp_p->base = base;
+ temp_p->mbase = 0;
+ temp_p->maddr = 0;
+ temp_p->pci_bus = 0;
+ temp_p->pci_device_fn = slot;
+ aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+ while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+ if (aic7xxx_chip_reset(temp_p) == -1)
+ temp_p->irq = 0;
+ else
+ temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+ temp_p->flags |= AHC_PAGESCBS;
+
+ switch (temp_p->irq)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+
+ default:
+ printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+ "level %d, ignoring.\n", temp_p->irq);
+ kfree(temp_p);
+ release_region(base, MAXREG - MINREG);
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+
+ /*
+ * We are commited now, everything has been checked and this card
+ * has been found, now we just set it up
+ */
+
+ /*
+ * Insert our new struct into the list at the end
+ */
+ if (list_p == NULL)
+ {
+ list_p = current_p = temp_p;
+ }
+ else
+ {
+ current_p = list_p;
+ while (current_p->next != NULL)
+ current_p = current_p->next;
+ current_p->next = temp_p;
+ }
+
+ switch (type)
+ {
+ case 0:
+ temp_p->board_name_index = 2;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[2], slot);
+ /* FALLTHROUGH */
+ case 1:
+ {
+ temp_p->chip = AHC_AIC7770 | AHC_EISA;
+ temp_p->features |= AHC_AIC7770_FE;
+ temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
+
+ /*
+ * Get the primary channel information. Right now we don't
+ * do anything with this, but someday we will be able to inform
+ * the mid-level SCSI code which channel is primary.
+ */
+ if (temp_p->board_name_index == 0)
+ {
+ temp_p->board_name_index = 3;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[3], slot);
+ }
+ if (temp_p->bios_control & CHANNEL_B_PRIMARY)
+ {
+ temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
+ }
+
+ if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+ {
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ }
+ else
+ {
+ temp_p->flags &= ~AHC_USEDEFAULTS;
+ temp_p->flags |= AHC_BIOS_ENABLED;
+ if ( (temp_p->bios_control & 0x20) == 0 )
+ {
+ temp_p->bios_address = 0xcc000;
+ temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
+ }
+ else
+ {
+ temp_p->bios_address = 0xd0000;
+ temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
+ }
+ }
+ temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+ temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+ if (temp_p->features & AHC_WIDE)
+ {
+ temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
+ temp_p->scsi_id_b = temp_p->scsi_id;
+ }
+ else
+ {
+ temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+ temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
+ }
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ break;
+ }
+
+ case 2:
+ case 3:
+ temp_p->chip = AHC_AIC7770 | AHC_VL;
+ temp_p->features |= AHC_AIC7770_FE;
+ if (type == 2)
+ temp_p->flags |= AHC_BIOS_ENABLED;
+ else
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
+ sxfrctl1 = STPWEN;
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ temp_p->board_name_index = 4;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at VLB %d\n",
+ board_names[2], slot);
+ switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
+ {
+ case 0x00:
+ temp_p->bios_address = 0xe0000;
+ break;
+ case 0x20:
+ temp_p->bios_address = 0xc8000;
+ break;
+ case 0x40:
+ temp_p->bios_address = 0xd0000;
+ break;
+ case 0x60:
+ temp_p->bios_address = 0xd8000;
+ break;
+ default:
+ break; /* can't get here */
+ }
+ break;
+
+ default: /* Won't get here. */
+ break;
+ }
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ {
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+ (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+ temp_p->irq,
+ (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
+ }
+
+ /*
+ * Set the FIFO threshold and the bus off time.
+ */
+ hostconf = aic_inb(temp_p, HOSTCONF);
+ aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+ aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+ slot++;
+ found++;
+ }
+
+#endif /* defined(__i386__) || defined(__alpha__) */
+
/*
* Now, we re-order the probed devices by BIOS address and BUS class.
* In general, we follow this algorithm to make the adapters show up
@@ -10391,7 +10665,7 @@
* instead of slowing down if those exist. That's hard to do with simple
* checksums though.
*/
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
"validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -10422,7 +10696,7 @@
}
else
{
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Performing Domain validation.\n",
p->host_no, CTL_OF_CMD(cmd));
@@ -10447,7 +10721,7 @@
}
else
{
- if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
(p->needdv & (1<<tindex)) )
{
printk(INFO_LEAD "Successfully completed Domain validation.\n",
@@ -10663,7 +10937,8 @@
* little-endian format.
*/
hscb->SCSI_cmd_length = cmd->cmd_len;
- hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
+ memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
+ hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
if (cmd->use_sg)
{
@@ -10675,10 +10950,11 @@
* differences and the kernel SG list uses virtual addresses where
* we need physical addresses.
*/
- int i;
+ int i, use_sg;
sg = (struct scatterlist *)cmd->request_buffer;
scb->sg_length = 0;
+ use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg);
/*
* Copy the segments into the SG array. NOTE!!! - We used to
* have the first entry both in the data_pointer area and the first
@@ -10686,29 +10962,32 @@
* entry in both places, but now we download the address of
* scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
*/
- for (i = 0; i < cmd->use_sg; i++)
+ for (i = 0; i < use_sg; i++)
{
- scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
- scb->sg_list[i].length = cpu_to_le32(sg[i].length);
- scb->sg_length += sg[i].length;
+ unsigned int len = sg_dma_len(sg+i);
+ scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
+ scb->sg_list[i].length = cpu_to_le32(len);
+ scb->sg_length += len;
}
/* Copy the first SG into the data pointer area. */
hscb->data_pointer = scb->sg_list[0].address;
hscb->data_count = scb->sg_list[0].length;
- scb->sg_count = cmd->use_sg;
- hscb->SG_segment_count = cmd->use_sg;
- hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
+ scb->sg_count = i;
+ hscb->SG_segment_count = i;
+ hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
}
else
{
if (cmd->request_bufflen)
{
- scb->sg_count = 1;
- scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+ unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
+ cmd->request_bufflen);
+ scb->sg_list[0].address = cpu_to_le32(address);
scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+ scb->sg_count = 1;
scb->sg_length = cmd->request_bufflen;
hscb->SG_segment_count = 1;
- hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+ hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
hscb->data_count = scb->sg_list[0].length;
hscb->data_pointer = scb->sg_list[0].address;
}
@@ -11991,7 +12270,7 @@
break;
case AHC_PCI:
default:
- printk("PCI %d/%d.\n", PCI_SLOT(p->pci_device_fn),
+ printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
PCI_FUNC(p->pci_device_fn));
break;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)