VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 7
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre3
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
jnc setbad
addw %bx, %bx
- .word 0xa7ff, spec_inits # JMP [BX+spec_inits]
+ jmp *spec_inits(%bx)
setmenu:
orb %al, %al # 80x25 is an exception
vesa1:
# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
# XXX: lodsw %gs:(%si), %ax # Get next mode in the list
- .byte 0x65, 0xAD # %gs seg prefix + lodsw
+ gs; lodsw
cmpw $0xffff, %ax # End of the table?
jz vesar
static int __init init_amd(struct cpuinfo_x86 *c)
{
u32 l, h;
- unsigned long flags;
int mbytes = max_mapnr >> (20-PAGE_SHIFT);
int r;
mbytes=508;
rdmsr(0xC0000082, l, h);
- if((l&0x0000FFFF)==0)
- {
+ if ((l&0x0000FFFF)==0) {
+ unsigned long flags;
l=(1<<0)|((mbytes/4)<<1);
- save_flags(flags);
- __cli();
+ local_irq_save(flags);
__asm__ __volatile__ ("wbinvd": : :"memory");
wrmsr(0xC0000082, l, h);
- restore_flags(flags);
+ local_irq_restore(flags);
printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
mbytes);
mbytes=4092;
rdmsr(0xC0000082, l, h);
- if((l&0xFFFF0000)==0)
- {
+ if ((l&0xFFFF0000)==0) {
+ unsigned long flags;
l=((mbytes>>2)<<22)|(1<<16);
- save_flags(flags);
- __cli();
+ local_irq_save(flags);
__asm__ __volatile__ ("wbinvd": : :"memory");
wrmsr(0xC0000082, l, h);
- restore_flags(flags);
+ local_irq_restore(flags);
printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
mbytes);
}
/*
* Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
*/
-static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+static void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
{
unsigned char ccr2, ccr3;
+ unsigned long flags;
/* we test for DEVID by checking whether CCR3 is writable */
- cli();
+ local_irq_save(flags);
ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, ccr3 ^ 0x80);
getCx86(0xc0); /* dummy to change bus */
*dir0 = getCx86(CX86_DIR0);
*dir1 = getCx86(CX86_DIR1);
}
- sti();
+ local_irq_restore(flags);
}
/*
{
if (Cx86_dir0_msb == 3) {
unsigned char ccr3, ccr5;
+ unsigned long flags;
- cli();
+ local_irq_save(flags);
ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
ccr5 = getCx86(CX86_CCR5);
if (ccr5 & 2)
setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */
setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
- sti();
+ local_irq_restore(flags);
if (ccr5 & 2) { /* possible wrong calibration done */
printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
if (dir0 == 5 || dir0 == 3)
{
unsigned char ccr3, ccr4;
+ unsigned long flags;
printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
- cli();
+ local_irq_save(flags);
ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
ccr4 = getCx86(CX86_CCR4);
setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */
setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
- sti();
+ local_irq_restore(flags);
}
} else
*
*/
-static char *serial_version = "5.05a";
-static char *serial_revdate = "2001-03-20";
+static char *serial_version = "5.05b";
+static char *serial_revdate = "2001-05-03";
/*
* Serial driver configuration section. Here are the various options:
if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
printk("serial: PNP device '");
- printk_pnp_dev_id(board->vendor, board->device);
+ printk_pnp_dev_id(dev->vendor, dev->device);
printk("' prepare failed\n");
return;
}
if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
printk("serial: PNP device '");
- printk_pnp_dev_id(board->vendor, board->device);
+ printk_pnp_dev_id(dev->vendor, dev->device);
printk("' activate failed\n");
return;
}
{
unsigned long oldval;
- if (!(board->subdevice & 0x1000))
+ if (!(pci_get_subdevice(dev) & 0x1000))
return(-1);
if (!enable) /* is there something to deinit? */
for (i=0; timedia_data[i].num; i++) {
ids = timedia_data[i].ids;
for (j=0; ids[j]; j++) {
- if (pci_get_subvendor(dev) == ids[j]) {
+ if (pci_get_subdevice(dev) == ids[j]) {
board->num_ports = timedia_data[i].num;
return 0;
}
return 0;
}
+static int
+#ifndef MODULE
+__devinit
+#endif
+pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+ return 0;
+}
/*
* This is the configuration table for all of the PCI serial boards
- * which we support.
+ * which we support. It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
*/
+enum pci_board_num_t {
+ pbn_b0_1_115200,
+ pbn_default = 0,
+
+ pbn_b0_2_115200,
+ pbn_b0_4_115200,
+
+ pbn_b0_1_921600,
+ pbn_b0_2_921600,
+ pbn_b0_4_921600,
+
+ pbn_b0_bt_1_115200,
+ pbn_b0_bt_2_115200,
+ pbn_b0_bt_1_460800,
+ pbn_b0_bt_2_460800,
+
+ pbn_b1_1_115200,
+ pbn_b1_2_115200,
+ pbn_b1_4_115200,
+ pbn_b1_8_115200,
+
+ pbn_b1_2_921600,
+ pbn_b1_4_921600,
+ pbn_b1_8_921600,
+
+ pbn_b1_2_1382400,
+ pbn_b1_4_1382400,
+ pbn_b1_8_1382400,
+
+ pbn_b2_8_115200,
+ pbn_b2_4_460800,
+ pbn_b2_8_460800,
+ pbn_b2_16_460800,
+ pbn_b2_4_921600,
+ pbn_b2_8_921600,
+
+ pbn_b2_bt_1_115200,
+ pbn_b2_bt_2_115200,
+ pbn_b2_bt_4_115200,
+ pbn_b2_bt_2_921600,
+
+ pbn_panacom,
+ pbn_panacom2,
+ pbn_panacom4,
+ pbn_plx_romulus,
+ pbn_oxsemi,
+ pbn_timedia,
+ pbn_intel_i960,
+ pbn_sgi_ioc3,
+#ifdef CONFIG_DDB5074
+ pbn_nec_nile4,
+#endif
+#if 0
+ pbn_dci_pccom8,
+#endif
+ pbn_xircom_combo,
+
+ pbn_siig10x_0,
+ pbn_siig10x_1,
+ pbn_siig10x_2,
+ pbn_siig10x_4,
+ pbn_siig20x_0,
+ pbn_siig20x_2,
+ pbn_siig20x_4,
+
+ pbn_computone_4,
+ pbn_computone_6,
+ pbn_computone_8,
+};
+
static struct pci_board pci_boards[] __devinitdata = {
/*
- * Vendor ID, Device ID,
- * Subvendor ID, Subdevice ID,
* PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
* Offset to get to next UART's registers,
* Register shift to use for memory-mapped I/O,
* Initialization function, first UART offset
*/
+
+ /* Generic serial board, pbn_b0_1_115200, pbn_default */
+ { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200,
+ pbn_default */
+
+ { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */
+ { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */
+
+ { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */
+ { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */
+ { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */
+
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
+
+ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */
+ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */
+ { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */
+ { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */
+
+ { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */
+ { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */
+ { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */
+
+ { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */
+ { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */
+ { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */
+
+ { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */
+ { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */
+ { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */
+ { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */
+ { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */
+ { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */
+
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
+
+ { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */
+ 0x400, 7, pci_plx9050_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */
+ 0x400, 7, pci_plx9050_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */
+ 0x400, 7, pci_plx9050_fn },
+ { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */
+ 0x20, 2, pci_plx9050_fn, 0x03 },
+ /* This board uses the size of PCI Base region 0 to
+ * signal now many ports are available */
+ { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
+ { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */
+ 0, 0, pci_timedia_fn },
+ /* EKF addition for i960 Boards form EKF with serial port */
+ { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */
+ 8<<2, 2, pci_inteli960ni_fn, 0x10000},
+ { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */
+ 1, 458333, 0, 0, 0, 0x20178 },
+#ifdef CONFIG_DDB5074
+ /*
+ * NEC Vrc-5074 (Nile 4) builtin UART.
+ * Conditionally compiled in since this is a motherboard device.
+ */
+ { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */
+ 64, 3, NULL, 0x300 },
+#endif
+#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ /* pbn_dci_pccom8 */
+ { SPCI_FL_BASE3, 8, 115200, 8 },
+#endif
+ { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */
+ 0, 0, pci_xircom_fn },
+
+ { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */
+ 0, 0, pci_siig20x_fn },
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */
+ 0, 0, pci_siig20x_fn },
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */
+ 0, 0, pci_siig20x_fn },
+
+ { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */
+ 0x40, 2, NULL, 0x200 },
+ { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */
+ 0x40, 2, NULL, 0x200 },
+ { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */
+ 0x40, 2, NULL, 0x200 },
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs. Returns 0 on success, 1 on failure.
+ */
+static int __devinit serial_pci_guess_board(struct pci_dev *dev,
+ struct pci_board *board)
+{
+ int num_iomem = 0, num_port = 0, first_port = -1;
+ int i;
+
+ /*
+ * If it is not a communications device or the programming
+ * interface is greater than 6, give up.
+ *
+ * (Should we try to make guesses for multiport serial devices
+ * later?)
+ */
+ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+ ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+ (dev->class & 0xff) > 6)
+ return 1;
+
+ for (i=0; i < 6; i++) {
+ if (IS_PCI_REGION_IOPORT(dev, i)) {
+ num_port++;
+ if (first_port == -1)
+ first_port = i;
+ }
+ if (IS_PCI_REGION_IOMEM(dev, i))
+ num_iomem++;
+ }
+
+ /*
+ * If there is 1 or 0 iomem regions, and exactly one port, use
+ * it.
+ */
+ if (num_iomem <= 1 && num_port == 1) {
+ board->flags = first_port;
+ return 0;
+ }
+ return 1;
+}
+
+static int __devinit serial_init_one(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ struct pci_board *board, tmp;
+ int rc;
+
+ board = &pci_boards[ent->driver_data];
+
+ rc = pci_enable_device(dev);
+ if (rc) return rc;
+
+ if (ent->driver_data == pbn_default &&
+ serial_pci_guess_board(dev, board))
+ return -ENODEV;
+ else if (serial_pci_guess_board(dev, &tmp) == 0) {
+ printk(KERN_INFO "Redundant entry in serial pci_table. "
+ "Please send the output of\n"
+ "lspci -vv, this message (%d,%d,%d,%d)\n"
+ "and the manufacturer and name of "
+ "serial board or modem board\n"
+ "to serial-pci-info@lists.sourceforge.net.\n",
+ dev->vendor, dev->device,
+ pci_get_subvendor(dev), pci_get_subdevice(dev));
+ }
+
+ start_pci_pnp_board(dev, board);
+
+ return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+ int i;
+
+ /*
+ * Iterate through all of the ports finding those that belong
+ * to this PCI device.
+ */
+ for(i = 0; i < NR_PORTS; i++) {
+ if (rs_table[i].dev != dev)
+ continue;
+ unregister_serial(i);
+ rs_table[i].dev = 0;
+ }
+ /*
+ * Now execute any board-specific shutdown procedure
+ */
+ for (i=0; i < NR_PCI_BOARDS; i++) {
+ struct pci_board_inst *brd = &serial_pci_board[i];
+
+ if (serial_pci_board[i].dev != dev)
+ continue;
+ if (brd->board.init_fn)
+ (brd->board.init_fn)(brd->dev, &brd->board, 0);
+ if (DEACTIVATE_FUNC(brd->dev))
+ (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+ serial_pci_board[i].dev = 0;
+ }
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
- SPCI_FL_BASE1, 8, 1382400 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
- SPCI_FL_BASE1, 4, 1382400 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
- SPCI_FL_BASE1, 2, 1382400 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
- SPCI_FL_BASE1, 8, 1382400 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
- SPCI_FL_BASE1, 4, 1382400 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
- SPCI_FL_BASE1, 2, 1382400 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
- SPCI_FL_BASE1, 8, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+ pbn_b1_8_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
- SPCI_FL_BASE1, 8, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+ pbn_b1_8_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
- SPCI_FL_BASE1, 4, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+ pbn_b1_4_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
- SPCI_FL_BASE1, 4, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+ pbn_b1_4_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
- SPCI_FL_BASE1, 2, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+ pbn_b1_2_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6,
- SPCI_FL_BASE1, 8, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+ pbn_b1_8_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1,
- SPCI_FL_BASE1, 8, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+ pbn_b1_8_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1,
- SPCI_FL_BASE1, 4, 921600 },
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+ pbn_b1_4_921600 },
+
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_1_115200 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 8, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_115200 },
+
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
/* VScom SPCOM800, from sl@s.pl */
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 8, 921600 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_921600 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 4, 921600 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_921600 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_KEYSPAN,
- PCI_SUBDEVICE_ID_KEYSPAN_SX2,
- SPCI_FL_BASE2, 2, 921600, /* IOMEM */
- 0x400, 7, pci_plx9050_fn },
+ PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+ pbn_panacom },
{ PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
- 0x400, 7, pci_plx9050_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom4 },
{ PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0x400, 7, pci_plx9050_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom2 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST4,
- SPCI_FL_BASE2, 4, 460800 },
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
+ pbn_b2_4_460800 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST8,
- SPCI_FL_BASE2, 8, 460800 },
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
+ pbn_b2_8_460800 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST16,
- SPCI_FL_BASE2, 16, 460800 },
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
+ pbn_b2_16_460800 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC,
- SPCI_FL_BASE2, 16, 460800 },
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
+ pbn_b2_16_460800 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_CHASE_PCIRAS,
- PCI_SUBDEVICE_ID_CHASE_PCIRAS4,
- SPCI_FL_BASE2, 4, 460800 },
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
+ pbn_b2_4_460800 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_CHASE_PCIRAS,
- PCI_SUBDEVICE_ID_CHASE_PCIRAS8,
- SPCI_FL_BASE2, 8, 460800 },
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
+ pbn_b2_8_460800 },
/* Megawolf Romulus PCI Serial Card, from Mike Hudson */
/* (Exoray@isys.ca) */
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
- 0x10b5, 0x106a,
- SPCI_FL_BASE2, 4, 921600,
- 0x20, 2, pci_plx9050_fn, 0x03 },
+ 0x10b5, 0x106a, 0, 0,
+ pbn_plx_romulus },
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE1, 4, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE1, 2, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE1, 8, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE1, 8, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
{ PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
- PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
- SPCI_FL_BASE0 , 4, 921600 },
+ PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0,
+ pbn_b0_4_921600 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 , 4, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_115200 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 , 2, 115200 },
- /* This board uses the size of PCI Base region 0 to
- * signal now many ports are available */
- { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 },
- { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
- PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID,
- SPCI_FL_BASE_TABLE, 1, 921600,
- 0, 0, pci_timedia_fn },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_115200 },
+
+ /* Digitan DS560-558, from jimd@esoft.com */
+ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_115200 },
+
+ /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+ { PCI_VENDOR_ID_USR, 0x1008,
+ PCI_ANY_ID, PCI_ANY_ID, },
+
+ /* Titan Electronic cards */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 1, 460800,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 1, 460800,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 1, 460800,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 1, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_1 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 1, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_1 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2, 1, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_1 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_4 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_4 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
- 0, 0, pci_siig10x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_4 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_4 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_4 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
- 0, 0, pci_siig20x_fn },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_4 },
+
/* Computone devices submitted by Doug McNash dmcnash@computone.com */
{ PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
- SPCI_FL_BASE0, 4, 921600, /* IOMEM */
- 0x40, 2, NULL, 0x200 },
+ 0, 0, pbn_computone_4 },
{ PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
- SPCI_FL_BASE0, 8, 921600, /* IOMEM */
- 0x40, 2, NULL, 0x200 },
+ 0, 0, pbn_computone_8 },
{ PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
- SPCI_FL_BASE0, 6, 921600, /* IOMEM */
- 0x40, 2, NULL, 0x200 },
- /* Digitan DS560-558, from jimd@esoft.com */
- { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE1, 1, 115200 },
- /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
- { PCI_VENDOR_ID_USR, 0x1008,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 115200 },
- /* Titan Electronic cards */
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 2, 921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 4, 921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 4, 921600 },
- /* EKF addition for i960 Boards form EKF with serial port */
- { PCI_VENDOR_ID_INTEL, 0x1960,
- 0xE4BF, PCI_ANY_ID,
- SPCI_FL_BASE0, 32, 921600, /* max 256 ports */
- 8<<2, 2, pci_inteli960ni_fn, 0x10000},
+ 0, 0, pbn_computone_6 },
+
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
+ { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+ PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
+
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_460800 },
+
/* RAStel 2 port modem, gerg@moreton.com.au */
{ PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+
+ /* EKF addition for i960 Boards form EKF with serial port */
+ { PCI_VENDOR_ID_INTEL, 0x1960,
+ 0xE4BF, PCI_ANY_ID, 0, 0,
+ pbn_intel_i960 },
+
+ /* Xircom Cardbus/Ethernet combos */
+ { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_xircom_combo },
+
/*
* Untested PCI modems, sent in from various folks...
*/
+
/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
{ PCI_VENDOR_ID_ROCKWELL, 0x1004,
- 0x1048, 0x1500,
- SPCI_FL_BASE1, 1, 115200 },
+ 0x1048, 0x1500, 0, 0,
+ pbn_b1_1_115200 },
+
{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
- 0xFF00, 0, SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,
- 1, 458333, 0, 0, 0, 0x20178 },
-#if CONFIG_DDB5074
+ 0xFF00, 0, 0, 0,
+ pbn_sgi_ioc3 },
+
+#ifdef CONFIG_DDB5074
/*
* NEC Vrc-5074 (Nile 4) builtin UART.
* Conditionally compiled in since this is a motherboard device.
*/
{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE0, 1, 520833,
- 64, 3, NULL, 0x300 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_nec_nile4 },
#endif
+
#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */
{ PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE3, 8, 115200,
- 8 },
-#endif
- /* Generic serial board */
- { 0, 0,
- 0, 0,
- SPCI_FL_BASE0, 1, 115200 },
-};
-
-/*
- * Given a complete unknown PCI device, try to use some heuristics to
- * guess what the configuration might be, based on the pitiful PCI
- * serial specs. Returns 0 on success, 1 on failure.
- */
-static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
- struct pci_board *board)
-{
- int num_iomem = 0, num_port = 0, first_port = -1;
- int i;
-
- /*
- * If it is not a communications device or the programming
- * interface is greater than 6, give up.
- *
- * (Should we try to make guesses for multiport serial devices
- * later?)
- */
- if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
- ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
- (dev->class & 0xff) > 6)
- return 1;
-
- for (i=0; i < 6; i++) {
- if (IS_PCI_REGION_IOPORT(dev, i)) {
- num_port++;
- if (first_port == -1)
- first_port = i;
- }
- if (IS_PCI_REGION_IOMEM(dev, i))
- num_iomem++;
- }
-
- /*
- * If there is 1 or 0 iomem regions, and exactly one port, use
- * it.
- */
- if (num_iomem <= 1 && num_port == 1) {
- board->flags = first_port;
- return 0;
- }
- return 1;
-}
-
-static int __devinit serial_init_one(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- struct pci_board *board, tmp;
- int rc;
-
- for (board = pci_boards; board->vendor; board++) {
- if (board->vendor != (unsigned short) PCI_ANY_ID &&
- dev->vendor != board->vendor)
- continue;
- if (board->device != (unsigned short) PCI_ANY_ID &&
- dev->device != board->device)
- continue;
- if (board->subvendor != (unsigned short) PCI_ANY_ID &&
- pci_get_subvendor(dev) != board->subvendor)
- continue;
- if (board->subdevice != (unsigned short) PCI_ANY_ID &&
- pci_get_subdevice(dev) != board->subdevice)
- continue;
- break;
- }
-
- rc = pci_enable_device(dev);
- if (rc) return rc;
-
- if (board->vendor == 0 && serial_pci_guess_board(dev, board))
- return -ENODEV;
- else if (serial_pci_guess_board(dev, &tmp) == 0) {
- printk(KERN_INFO "Redundant entry in serial pci_table. "
- "Please send the output of\n"
- "lspci -vv, this message (%d,%d,%d,%d)\n"
- "and the manufacturer and name of "
- "serial board or modem board\n"
- "to serial-pci-info@lists.sourceforge.net.\n",
- dev->vendor, dev->device,
- pci_get_subvendor(dev), pci_get_subdevice(dev));
- }
-
- start_pci_pnp_board(dev, board);
-
- return 0;
-}
-
-static void __devexit serial_remove_one(struct pci_dev *dev)
-{
- int i;
-
- /*
- * Iterate through all of the ports finding those that belong
- * to this PCI device.
- */
- for(i = 0; i < NR_PORTS; i++) {
- if (rs_table[i].dev != dev)
- continue;
- unregister_serial(i);
- rs_table[i].dev = 0;
- }
- /*
- * Now execute any board-specific shutdown procedure
- */
- for (i=0; i < NR_PCI_BOARDS; i++) {
- struct pci_board_inst *brd = &serial_pci_board[i];
-
- if (serial_pci_board[i].dev != dev)
- continue;
- if (brd->board.init_fn)
- (brd->board.init_fn)(brd->dev, &brd->board, 0);
- if (DEACTIVATE_FUNC(brd->dev))
- (DEACTIVATE_FUNC(brd->dev))(brd->dev);
- serial_pci_board[i].dev = 0;
- }
-}
-
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_dci_pccom8 },
+#endif
-static struct pci_device_id serial_pci_tbl[] __devinitdata = {
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
* not to attempt to unregister the driver later
*/
if (pci_module_init (&serial_pci_driver) != 0)
- serial_pci_driver.name[0] = 0;
+ serial_pci_driver.name = "";
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
break;
if (pnp_board->vendor) {
- board.vendor = pnp_board->vendor;
- board.device = pnp_board->device;
/* Special case that's more efficient to hardcode */
- if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
- board.device == ISAPNP_DEVICE(0x1021)))
+ if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+ pnp_board->device == ISAPNP_DEVICE(0x1021)))
board.flags |= SPCI_FL_NO_SHIRQ;
} else {
if (serial_pnp_guess_board(dev, &board))
BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
unsigned char Bus = PCI_Device->bus->number;
unsigned char Device = PCI_Device->devfn >> 3;
- unsigned int IRQ_Channel = PCI_Device->irq;
- unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0);
- unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1);
- BusLogic_IO_Address_T IO_Address = BaseAddress0;
- BusLogic_PCI_Address_T PCI_Address = BaseAddress1;
+ unsigned int IRQ_Channel;
+ unsigned long BaseAddress0;
+ unsigned long BaseAddress1;
+ BusLogic_IO_Address_T IO_Address;
+ BusLogic_PCI_Address_T PCI_Address;
if (pci_enable_device(PCI_Device))
continue;
+ IRQ_Channel = PCI_Device->irq;
+ IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0);
+ PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1);
+
if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM)
{
BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
int SynchronousTransferRate = 0;
if (BusLogic_FlashPointHostAdapterP(HostAdapter))
{
- boolean WideTransfersActive;
+ unsigned char WideTransfersActive;
FlashPoint_InquireTargetInfo(
HostAdapter->CardHandle, TargetID,
&HostAdapter->SynchronousPeriod[TargetID],
reset: BusLogic_ResetCommand, /* Reset Command Function */ \
bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \
unchecked_isa_dma: 1, /* Default Initial Value */ \
+ max_sectors: 128, /* I/O queue len limit */ \
use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */
+Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr)
+ * version ncr53c8xx-3.4.3b
+ - Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM.
+ Fix sent by Stig Telfer <stig@api-networks.com>.
+ - Define scsi_set_pci_device() as nil for kernel < 2.4.4.
+
Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr)
* version ncr53c8xx-3.4.3
- Call pci_enable_device() as AC wants this to be done.
- Changes from Eddie Dost for Sparc and Alpha:
ioremap/iounmap support for Sparc.
pcivtophys changed to bus_dvma_to_phys.
- - Add the 53c876 description to the chip table. This is only usefull
+ - Add the 53c876 description to the chip table. This is only useful
for printing the right name of the controller.
- DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15).
- Add additionnal checking of INQUIRY data:
Sat Jun 20 20:00 1998 Gerard Roudier (groudier@club-internet.fr)
* revision 3.0c
- Add a boot setup option that allows to set up device queue depths
- at boot-up. This option is very usefull since Linux does not
+ at boot-up. This option is very useful since Linux does not
allow to change scsi device queue depth once the system has been
booted up.
kernel version >= 2.1.105.
- Replace all printf(s) by printk(s). After all, the ncr53c8xx is
a driver for Linux.
- - Perform auto-sense on COMMAND TERMINATED. Not sure it is usefull.
+ - Perform auto-sense on COMMAND TERMINATED. Not sure it is useful.
- Some other minor changes.
Tue Jun 4 23:00 1998 Gerard Roudier (groudier@club-internet.fr)
- Code cleanup and simplification:
Remove kernel 1.2.X and 1.3.X support.
Remove the _old_ target capabilities table.
- Remove the error recovery code that have'nt been really usefull.
+ Remove the error recovery code that have'nt been really useful.
Use a single alignment boundary (CACHE_LINE_SIZE) for data
structures.
- Several aggressive SCRIPTS optimizations and changes:
+Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.7.3c
+ - Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM.
+ Fix sent by Stig Telfer <stig@api-networks.com>.
+ - Backport from SYM-2 the work-around that allows to support
+ hardwares that fail PCI parity checking.
+ - Check that we received at least 8 bytes of INQUIRY response
+ for byte 7, that contains device capabilities, to be valid.
+ - Define scsi_set_pci_device() as nil for kernel < 2.4.4.
+ - + A couple of minor changes.
+
+Sat Apr 7 19:30 2001 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.7.3b
+ - Fix an unaligned LOAD from scripts (was used as dummy read).
+ - In ncr_soft_reset(), only try to ABORT the current operation
+ for chips that support SRUN bit in ISTAT1 and if SCRIPTS are
+ currently running, as 896 and 1010 manuals suggest.
+ - In the CCB abort path, donnot assume that the CCB is currently
+ queued to SCRIPTS. This is not always true, notably after a
+ QUEUE FULL status or when using untagged commands.
+
Sun Mar 4 18:30 2001 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.7.3a
- Fix an issue in the ncr_int_udc() (unexpected disconnect)
Tue Apr 15 10:00 1999 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.3e
- Support for any number of LUNs (64) (SPI2-compliant).
- (Btw, this may only be ever usefull under linux-2.2 ;-))
+ (Btw, this may only be ever useful under linux-2.2 ;-))
Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.3d
bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP
fi
+if [ "$CONFIG_AMIGA" = "y" ]; then
+ dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'A4000T SCSI support (EXPERIMENTAL)' CONFIG_A4000T_SCSI
+ fi
+fi
+if [ "$CONFIG_ZORRO" = "y" ]; then
+ dep_tristate 'A2091/A590 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI
+ dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI
+ dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI
+ dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI
+ dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI
+ dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI
+ dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'A4091 SCSI support (EXPERIMENTAL)' CONFIG_A4091_SCSI
+ bool 'WarpEngine SCSI support (EXPERIMENTAL)' CONFIG_WARPENGINE_SCSI
+ bool 'Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)' CONFIG_BLZ603EPLUS_SCSI
+ dep_tristate 'BSC Oktagon SCSI support (EXPERIMENTAL)' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
+# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
+# bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI
+ fi
+fi
+
endmenu
if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
#if (FW_TYPE==_UCB_MGR_)
#define HBA_AUTO_SENSE_FAIL 0x1B
#define HBA_TQ_REJECTED 0x1C
- #define HBA_UNSUPORTED_MSG 0x1D
+ #define HBA_UNSUPPORTED_MSG 0x1D
#define HBA_HW_ERROR 0x20
#define HBA_ATN_NOT_RESPONDED 0x21
#define HBA_SCSI_RESET_BY_ADAPTER 0x22
--- /dev/null
+ AIC7xxx Driver for Linux
+
+Introduction
+----------------------------
+The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
+SCSI controllers and chipsets. Major portions of the driver and driver
+development are shared between both Linux and FreeBSD. Support for the
+AIC-7xxx chipsets have been in the default Linux kernel since approximately
+linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
+2.1.0 or later.
+
+ Supported cards/chipsets
+ ----------------------------
+ Adaptec Cards
+ ----------------------------
+ AHA-274x
+ AHA-274xT
+ AHA-274xW
+ AHA-284x
+ AHA-284xW
+ All PCI based cards using any of the chipsets listed under motherboard
+ chipsets. In general, this means *all* of the Adaptec SCSI controllers
+ except the ones specifically excluded later on in this document.
+
+ Motherboard Chipsets
+ ----------------------------
+ AIC-777x
+ AIC-785x
+ AIC-786x
+ AIC-787x
+ AIC-788x
+ AIC-789x
+ AIC-3860
+
+ Bus Types
+ ----------------------------
+ W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
+ SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
+ U - Ultra SCSI, transfer rates up to 40MB/s.
+ U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
+ U3- Ultra 3 SCSI, transfer rates up to 160MB/s.
+ D - Differential SCSI.
+ T - Twin Channel SCSI. Up to 14 SCSI devices.
+
+ AHA-274x - EISA SCSI controller
+ AHA-284x - VLB SCSI controller
+ AHA-29xx - PCI SCSI controller
+ AHA-39xx - PCI controllers with multiple separate SCSI channels on-board.
+
+ Not Supported Devices
+ ------------------------------
+ Adaptec Cards
+ ----------------------------
+ AHA-2920 (Only the cards that use the Future Domain chipset are not
+ supported, any 2920 cards based on Adaptec AIC chipsets,
+ such as the 2920C, are supported)
+ AAA-13x Raid Adapters
+ AAA-113x Raid Port Card
+
+ Motherboard Chipsets
+ ----------------------------
+ AIC-781x
+
+ Bus Types
+ ----------------------------
+ R - Raid Port busses are not supported.
+
+ The hardware RAID devices sold by Adaptec are *NOT* supported by this
+ driver (and will people please stop emailing me about them, they are
+ a totally separate beast from the bare SCSI controllers and this driver
+ can not be retrofitted in any sane manner to support the hardware RAID
+ features on those cards - Doug Ledford).
+
+
+ People
+ ------------------------------
+ Justin T Gibbs gibbs@plutotech.com
+ (BSD Driver Author)
+ Dan Eischen deischen@iworks.InterWorks.org
+ (Original Linux Driver Co-maintainer)
+ Dean Gehnert deang@teleport.com
+ (Original Linux FTP/patch maintainer)
+ Jess Johnson jester@frenzy.com
+ (AIC7xxx FAQ author)
+ Doug Ledford dledford@redhat.com
+ (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
+
+ Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
+ author of the driver. John has since retired from the project. Thanks
+ again for all his work!
+
+ Mailing list
+ ------------------------------
+ There is a mailing list available for users who want to track development
+ and converse with other users and developers. This list is for both
+ FreeBSD and Linux support of the AIC7xxx chipsets.
+
+ To subscribe to the AIC7xxx mailing list send mail to the list server,
+ with "subscribe AIC7xxx" in the body (no Subject: required):
+ To: majordomo@FreeBSD.ORG
+ ---
+ subscribe AIC7xxx
+
+ To unsubscribe from the list, send mail to the list server with:
+ To: majordomo@FreeBSD.ORG
+ ---
+ unsubscribe AIC7xxx
+
+ Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
+
+ Boot Command line options
+ ------------------------------
+ "aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup.
+ Some SCSI devices need the initial reset that this option disables
+ in order to work. If you have problems at bootup, please make sure
+ you aren't using this option.
+
+ "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at
+ bootup by scanning from the highest numbered PCI device to the
+ lowest numbered PCI device, others do just the opposite and scan
+ from lowest to highest numbered PCI device. There is no reliable
+ way to autodetect this ordering. So, we default to the most common
+ order, which is lowest to highest. Then, in case your motherboard
+ scans from highest to lowest, we have this option. If your BIOS
+ finds the drives on controller A before controller B but the linux
+ kernel finds your drives on controller B before A, then you should
+ use this option.
+
+ "aic7xxx=extended" - Force the driver to detect extended drive translation
+ on your controller. This helps those people who have cards without
+ a SEEPROM make sure that linux and all other operating systems think
+ the same way about your hard drives.
+
+ "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to
+ give the card more hardware SCB slots. This allows the driver to use
+ that SCB RAM. Without this option, the driver won't touch the SCB
+ RAM because it is known to cause problems on a few cards out there
+ (such as 3985 class cards).
+
+ "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+ to use the correct IRQ type for your card. This only applies to EISA
+ based controllers. On these controllers, 0 is for Edge triggered
+ interrupts, and 1 is for Level triggered interrupts. If you aren't
+ sure or don't know which IRQ trigger type your EISA card uses, then
+ let the kernel autodetect the trigger type.
+
+ "aic7xxx=verbose" - This option can be used in one of two ways. If you
+ simply specify aic7xxx=verbose, then the kernel will automatically
+ pick the default set of verbose messages for you to see.
+ Alternatively, you can specify the command as
+ "aic7xxx=verbose:0xXXXX" where the X entries are replaced with
+ hexadecimal digits. This option is a bit field type option. For
+ a full listing of the available options, search for the
+ #define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want
+ verbose messages, then it is recommended that you simply use the
+ aic7xxx=verbose variant of this command.
+
+ "aic7xxx=pci_parity:x" - This option controls whether or not the driver
+ enables PCI parity error checking on the PCI bus. By default, this
+ checking is disabled. To enable the checks, simply specify pci_parity
+ with no value afterwords. To reverse the parity from even to odd,
+ supply any number other than 0 or 255. In short:
+ pci_parity - Even parity checking (even is the normal PCI parity)
+ pci_parity:x - Where x > 0, Odd parity checking
+ pci_parity:0 - No check (default)
+ NOTE: In order to get Even PCI parity checking, you must use the
+ version of the option that does not include the : and a number at
+ the end (unless you want to enter exactly 2^32 - 1 as the number).
+
+ "aic7xxx=no_probe" - This option will disable the probing for any VLB
+ based 2842 controllers and any EISA based controllers. This is
+ needed on certain newer motherboards where the normal EISA I/O ranges
+ have been claimed by other PCI devices. Probing on those machines
+ will often result in the machine crashing or spontaneously rebooting
+ during startup. Examples of machines that need this are the
+ Dell PowerEdge 6300 machines.
+
+ "aic7xxx=seltime:2" - This option controls how long the card waits
+ during a device selection sequence for the device to respond.
+ The original SCSI spec says that this "should be" 256ms. This
+ is generally not required with modern devices. However, some
+ very old SCSI I devices need the full 256ms. Most modern devices
+ can run fine with only 64ms. The default for this option is
+ 64ms. If you need to change this option, then use the following
+ table to set the proper value in the example above:
+ 0 - 256ms
+ 1 - 128ms
+ 2 - 64ms
+ 3 - 32ms
+
+ "aic7xxx=panic_on_abort" - This option is for debugging and will cause
+ the driver to panic the linux kernel and freeze the system the first
+ time the drivers abort or reset routines are called. This is most
+ helpful when some problem causes infinite reset loops that scroll too
+ fast to see. By using this option, you can write down what the errors
+ actually are and send that information to me so it can be fixed.
+
+ "aic7xxx=dump_card" - This option will print out the *entire* set of
+ configuration registers on the card during the init sequence. This
+ is a debugging aid used to see exactly what state the card is in
+ when we finally finish our initialization routines. If you don't
+ have documentation on the chipsets, this will do you absolutely
+ no good unless you are simply trying to write all the information
+ down in order to send it to me.
+
+ "aic7xxx=dump_sequencer" - This is the same as the above options except
+ that instead of dumping the register contents on the card, this
+ option dumps the contents of the sequencer program RAM. This gives
+ the ability to verify that the instructions downloaded to the
+ card's sequencer are indeed what they are suppossed to be. Again,
+ unless you have documentation to tell you how to interpret these
+ numbers, then it is totally useless.
+
+ "aic7xxx=override_term:0xffffffff" - This option is used to force the
+ termination on your SCSI controllers to a particular setting. This
+ is a bit mask variable that applies for up to 8 aic7xxx SCSI channels.
+ Each channel gets 4 bits, divided as follows:
+ bit 3 2 1 0
+ | | | Enable/Disable Single Ended Low Byte Termination
+ | | En/Disable Single Ended High Byte Termination
+ | En/Disable Low Byte LVD Termination
+ En/Disable High Byte LVD Termination
+
+ The upper 2 bits that deal with LVD termination only apply to Ultra2
+ controllers. Futhermore, due to the current Ultra2 controller
+ designs, these bits are tied together such that setting either bit
+ enables both low and high byte LVD termination. It is not possible
+ to only set high or low byte LVD termination in this manner. This is
+ an artifact of the BIOS definition on Ultra2 controllers. For other
+ controllers, the only important bits are the two lowest bits. Setting
+ the higher bits on non-Ultra2 controllers has no effect. A few
+ examples of how to use this option:
+
+ Enable low and high byte termination on a non-ultra2 controller that
+ is the first aic7xxx controller (the correct bits are 0011),
+ aic7xxx=override_term:0x3
+
+ Enable all termination on the third aic7xxx controller, high byte
+ termination on the second aic7xxx controller, and low and high byte
+ SE termination on the first aic7xxx controller
+ (bits are 1111 0010 0011),
+ aic7xxx=override_term:0xf23
+
+ No attempt has been made to make this option non-cryptic. It really
+ shouldn't be used except in dire circumstances, and if that happens,
+ I'm probably going to be telling you what to set this to anyway :)
+
+ "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV
+ bit in the DEVCONFIG PCI register. Currently, this is one of the
+ very few registers that we have absolutely *no* way of detecting
+ what the variable should be. It depends entirely on how the chipset
+ and external terminators were coupled by the card/motherboard maker.
+ Further, a chip reset (at power up) always sets this bit to 0. If
+ there is no BIOS to run on the chipset/card (such as with a 2910C
+ or a motherboard controller with the BIOS totally disabled) then
+ the variable may not get set properly. Of course, if the proper
+ setting was 0, then that's what it would be after the reset, but if
+ the proper setting is actually 1.....you get the picture. Now, since
+ we can't detect this at all, I've added this option to force the
+ setting. If you have a BIOS on your controller then you should never
+ need to use this option. However, if you are having lots of SCSI
+ reset problems and can't seem to get them knocked out, this may help.
+
+ Here's a test to know for certain if you need this option. Make
+ a boot floppy that you can use to boot your computer up and that
+ will detect the aic7xxx controller. Next, power down your computer.
+ While it's down, unplug all SCSI cables from your Adaptec SCSI
+ controller. Boot the system back up to the Adaptec EZ-SCSI BIOS
+ and then make sure that termination is enabled on your adapter (if
+ you have an Adaptec BIOS of course). Next, boot up the floppy you
+ made and wait for it to detect the aic7xxx controller. If the kernel
+ finds the controller fine, says scsi : x hosts and then tries to
+ detect your devices like normal, up to the point where it fails to
+ mount your root file system and panics, then you're fine. If, on
+ the other hand, the system goes into an infinite reset loop, then
+ you need to use this option and/or the previous option to force the
+ proper termination settings on your controller. If this happens,
+ then you next need to figure out what your settings should be.
+
+ To find the correct settings, power your machine back down, connect
+ back up the SCSI cables, and boot back into your machine like normal.
+ However, boot with the aic7xxx=verbose:0x39 option. Record the
+ initial DEVCONFIG values for each of your aic7xxx controllers as
+ they are listed, and also record what the machine is detecting as
+ the proper termination on your controllers. NOTE: the order in
+ which the initial DEVCONFIG values are printed out is not gauranteed
+ to be the same order as the SCSI controllers are registered. The
+ above option and this option both work on the order of the SCSI
+ controllers as they are registered, so make sure you match the right
+ DEVCONFIG values with the right controllers if you have more than
+ one aic7xxx controller.
+
+ Once you have the detected termination settings and the initial
+ DEVCONFIG values for each controller, then figure out what the
+ termination on each of the controllers *should* be. Hopefully, that
+ part is correct, but it could possibly be wrong if there is
+ bogus cable detection logic on your controller or something similar.
+ If all the controllers have the correct termination settings, then
+ don't set the aic7xxx=override_term variable at all, leave it alone.
+ Next, on any controllers that go into an infinite reset loop when
+ you unplug all the SCSI cables, get the starting DEVCONFIG value.
+ If the initial DEVCONFIG value is divisible by 2, then the correct
+ setting for that controller is 0. If it's an odd number, then
+ the correct setting for that controller is 1. For any other
+ controllers that didn't have an infinite reset problem, then reverse
+ the above options. If DEVCONFIG was even, then the correct setting
+ is 1, if not then the correct setting is 0.
+
+ Now that you know what the correct setting was for each controller,
+ we need to encode that into the aic7xxx=stpwlev:0x... variable.
+ This variable is a bit field encoded variable. Bit 0 is for the first
+ aic7xxx controller, bit 1 for the next, etc. Put all these bits
+ together and you get a number. For example, if the third aic7xxx
+ needed a 1, but the second and first both needed a 0, then the bits
+ would be 100 in binary. This then translates to 0x04. You would
+ therefore set aic7xxx=stpwlev:0x04. This is fairly standard binary
+ to hexadecimal conversions here. If you aren't up to speed on the
+ binary->hex conversion then send an email to the aic7xxx mailing
+ list and someone can help you out.
+
+ "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
+ or enable Tagged Command Queueing (TCQ) on specific devices. As of
+ driver version 5.1.11, TCQ is now either on or off by default
+ according to the setting you choose during the make config process.
+ In order to en/disable TCQ for certian devices at boot time, a user
+ may use this boot param. The driver will then parse this message out
+ and en/disable the specific device entries that are present based upon
+ the value given. The param line is parsed in the following manner:
+
+ { - first instance indicates the start of this parameter values
+ second instance is the start of entries for a particular
+ device entry
+ } - end the entries for a particular host adapter, or end the entire
+ set of parameter entries
+ , - move to next entry. Inside of a set of device entries, this
+ moves us to the next device on the list. Outside of device
+ entries, this moves us to the next host adapter
+ . - Same effect as , but is safe to use with insmod.
+ x - the number to enter into the array at this position.
+ 0 = Enable tagged queueing on this device and use the default
+ queue depth
+ 1-254 = Enable tagged queueing on this device and use this
+ number as the queue depth
+ 255 = Disable tagged queueing on this device.
+ Note: anything above 32 for an actual queue depth is wasteful
+ and not recommended.
+
+ A few examples of how this can be used:
+
+ tag_info:{{8,12,,0,,255,4}}
+ This line will only effect the first aic7xxx card registered. It
+ will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+ at the default, set id 3 to tagged queueing enabled and use the
+ default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+ Any not specified entries stay at the default value, repeated
+ commas with no value specified will simply increment to the next id
+ without changing anything for the missing values.
+
+ tag_info:{,,,{,,,255}}
+ First, second, and third adapters at default values. Fourth
+ adapter, id 3 is disabled. Notice that leading commas simply
+ increment what the first number effects, and there are no need
+ for trailing commas. When you close out an adapter, or the
+ entire entry, anything not explicitly set stays at the default
+ value.
+
+ A final note on this option. The scanner I used for this isn't
+ perfect or highly robust. If you mess the line up, the worst that
+ should happen is that the line will get ignored. If you don't
+ close out the entire entry with the final bracket, then any other
+ aic7xxx options after this will get ignored. So, in general, be
+ sure of what you are entering, and after you have it right, just
+ add it to the lilo.conf file so there won't be any mistakes. As
+ a means of checking this parser, the entire tag_info array for
+ each card is now printed out in the /proc/scsi/aic7xxx/x file. You
+ can use that to verify that your options were parsed correctly.
+
+ Boot command line options may be combined to form the proper set of options
+ a user might need. For example, the following is valid:
+
+ aic7xxx=verbose,extended,irq_trigger:1
+
+ The only requirement is that individual options be separated by a comma or
+ a period on the command line.
+
+ Module Loading command options
+ ------------------------------
+ When loading the aic7xxx driver as a module, the exact same options are
+ available to the user. However, the syntax to specify the options changes
+ slightly. For insmod, you need to wrap the aic7xxx= argument in quotes
+ and replace all ',' with '.'. So, for example, a valid insmod line
+ would be:
+
+ insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+ This line should result in the *exact* same behaviour as if you typed
+ it in at the lilo prompt and the driver was compiled into the kernel
+ instead of being a module. The reason for the single quote is so that
+ the shell won't try to interpret anything in the line, such as {.
+ Insmod assumes any options starting with a letter instead of a number
+ is a character string (which is what we want) and by switching all of
+ the commas to periods, insmod won't interpret this as more than one
+ string and write junk into our binary image. I consider it a bug in
+ the insmod program that even if you wrap your string in quotes (quotes
+ that pass the shell mind you and that insmod sees) it still treates
+ a comma inside of those quotes as starting a new variable, resulting
+ in memory scribbles if you don't switch the commas to periods.
+
+
+ Kernel Compile options
+ ------------------------------
+ The various kernel compile time options for this driver are now fairly
+ well documented in the file Documentation/Configure.help. In order to
+ see this documentation, you need to use one of the advanced configuration
+ programs (menuconfig and xconfig). If you are using the "make menuconfig"
+ method of configuring your kernel, then you would simply highlight the
+ option in question and hit the ? key. If you are using the "make xconfig"
+ method of configuring your kernel, then simply click on the help button
+ next to the option you have questions about. The help information from
+ the Configure.help file will then get automatically displayed.
+
+ /proc support
+ ------------------------------
+ The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
+ directory. That directory contains a file for each SCSI controller in
+ the system. Each file presents the current configuration and transfer
+ statistics (enabled with #define in aic7xxx.c) for each controller.
+
+ Thanks to Michael Neuffer for his upper-level SCSI help, and
+ Matthew Jacob for statistics support.
+
+ Debugging the driver
+ ------------------------------
+ Should you have problems with this driver, and would like some help in
+ getting them solved, there are a couple debugging items built into
+ the driver to facilitate getting the needed information from the system.
+ In general, I need a complete description of the problem, with as many
+ logs as possible concerning what happens. To help with this, there is
+ a command option aic7xxx=panic_on_abort. This option, when set, forces
+ the driver to panic the kernel on the first SCSI abort issued by the
+ mid level SCSI code. If your system is going to reset loops and you
+ can't read the screen, then this is what you need. Not only will it
+ stop the system, but it also prints out a large amount of state
+ information in the process. Second, if you specify the option
+ "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
+ information as it runs that you won't be able to see anything.
+ However, this can actually be very useful if your machine simply
+ locks up when trying to boot, since it will pin-point what was last
+ happening (in regards to the aic7xxx driver) immediately prior to
+ the lockup. This is really only useful if your machine simply can
+ not boot up successfully. If you can get your machine to run, then
+ this will produce far too much information.
+
+ FTP sites
+ ------------------------------
+ ftp://ftp.redhat.com/pub/aic/
+ - Out of date. I used to keep stuff here, but too many people
+ complained about having a hard time getting into Red Hat's ftp
+ server. So use the web site below instead.
+ ftp://ftp.pcnet.com/users/eischen/Linux/
+ - Dan Eischen's driver distribution area
+ ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
+ - European Linux mirror of Teleport site
+
+ Web sites
+ ------------------------------
+ http://people.redhat.com/dledford/
+ - My web site, also the primary aic7xxx site with several related
+ pages.
+
+Dean W. Gehnert
+deang@teleport.com
+
+$Revision: 3.0 $
+
+Modified by Doug Ledford 1998-2000
+
clearprof
The profile counters are automatically cleared when the amount of
- data transfered reaches 1000 GB in order to avoid overflow.
+ data transferred reaches 1000 GB in order to avoid overflow.
The "clearprof" command allows you to clear these counters at any time.
The use of IARB needs the SCSI_NCR_IARB_SUPPORT option to have been defined
at compile time and the 'iarb' boot option to have been set to a non zero
-value at boot time. It is not that usefull for real work, but can be used
+value at boot time. It is not that useful for real work, but can be used
to stress SCSI devices or for some applications that can gain advantage of
it. By the way, if you experience badnesses like 'unexpected disconnections',
'bad reselections', etc... when using IARB on heavy IO load, you should not
Bit 0x04 : UDC Undexpected Disconnection
Indicates that the device released the SCSI BUS when the chip
was not expecting this to happen. A device may behave so to
- indicate the SCSI initiator that an error condition not reportable using the SCSI protocol has occured.
+ indicate the SCSI initiator that an error condition not reportable using the SCSI protocol has occurred.
Bit 0x02 : RST SCSI BUS Reset
Generally SCSI targets donnot reset the SCSI BUS, although any
device on the BUS can reset it at any time.
static int ahc_linux_pci_dev_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#include <linux/module.h>
+
static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
-/* We do our own ID filtering. So, grab all SCSI storage class devices. */
+/* We do our own ID filtering. So we grab all Adaptec SCSI storage class
+ * devices here.
+ */
static struct pci_device_id ahc_linux_pci_id_table[] = {
{
0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
},
{ 0 }
};
+MODULE_DEVICE_TABLE(pci,ahc_linux_pci_id_table);
struct pci_driver aic7xxx_pci_driver = {
name: "aic7xxx",
#include <scsi/scsicam.h>
#include <linux/stat.h>
-#include <linux/malloc.h> /* for kmalloc() */
+#include <linux/slab.h> /* for kmalloc() */
#include <linux/config.h> /* for CONFIG_PCI */
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-#define AIC7XXX_C_VERSION "5.2.1"
+#define AIC7XXX_C_VERSION "5.2.4"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
* You can try raising me if tagged queueing is enabled, or lowering
* me if you only have 4 SCBs.
*/
-#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
-#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
#else
#define AIC7XXX_CMDS_PER_DEVICE 8
#endif
* NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
* NOTE: This does affect performance since it has to maintain statistics.
*/
-#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS
+#ifdef CONFIG_AIC7XXX_PROC_STATS
#define AIC7XXX_PROC_STATS
#endif
* Make a define that will tell the driver not to use tagged queueing
* by default.
*/
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
0, 0, 0, 0, 0, 0, 0, 0}
#else
/*28*/ unsigned int pad; /*
* Unused by the kernel, but we require
* the padding so that the array of
- * hardware SCBs is alligned on 32 byte
+ * hardware SCBs is aligned on 32 byte
* boundaries so the sequencer can index
*/
};
typedef enum {
SCB_FREE = 0x0000,
+ SCB_DTR_SCB = 0x0001,
SCB_WAITINGQ = 0x0002,
SCB_ACTIVE = 0x0004,
SCB_SENSE = 0x0008,
unsigned int dma_len; /* DMA length */
};
+typedef enum {
+ AHC_BUG_NONE = 0x0000,
+ AHC_BUG_TMODE_WIDEODD = 0x0001,
+ AHC_BUG_AUTOFLUSH = 0x0002,
+ AHC_BUG_CACHETHEN = 0x0004,
+ AHC_BUG_CACHETHEN_DIS = 0x0008,
+ AHC_BUG_PCI_2_1_RETRY = 0x0010,
+ AHC_BUG_PCI_MWI = 0x0020,
+ AHC_BUG_SCBCHAN_UPLOAD = 0x0040,
+} ahc_bugs;
+
struct aic7xxx_scb {
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
unsigned long isr_count; /* Interrupt count */
unsigned long spurious_int;
scb_data_type *scb_data;
- volatile unsigned short needdv;
volatile unsigned short needppr;
volatile unsigned short needsdtr;
volatile unsigned short needwdtr;
#define BUS_DEVICE_RESET_PENDING 0x02
#define DEVICE_RESET_DELAY 0x04
#define DEVICE_PRINT_DTR 0x08
-#define DEVICE_PARITY_ERROR 0x10
-#define DEVICE_WAS_BUSY 0x20
-#define DEVICE_SCSI_3 0x40
-#define DEVICE_SCANNED 0x80
+#define DEVICE_WAS_BUSY 0x10
+#define DEVICE_SCSI_3 0x20
+#define DEVICE_DTR_SCANNED 0x40
volatile unsigned char dev_flags[MAX_TARGETS];
volatile unsigned char dev_active_cmds[MAX_TARGETS];
volatile unsigned char dev_temp_queue_depth[MAX_TARGETS];
spinlock_t spin_lock;
volatile unsigned char cpu_lock_count[NR_CPUS];
- Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS];
-
- unsigned int dev_checksum[MAX_TARGETS];
-
unsigned char dev_last_queue_full[MAX_TARGETS];
unsigned char dev_last_queue_full_count[MAX_TARGETS];
unsigned char dev_max_queue_depth[MAX_TARGETS];
int host_no; /* SCSI host number */
unsigned long mbase; /* I/O memory address */
ahc_chip chip; /* chip type */
+ ahc_bugs bugs;
dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
/*
{
p->flags &= ~AHC_ABORT_PENDING;
}
- if (scb->flags & SCB_RESET)
+ if (scb->flags & (SCB_RESET|SCB_ABORT))
{
- cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+ cmd->result |= (DID_RESET << 16);
}
- else if (scb->flags & SCB_ABORT)
- {
- cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
- }
- else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+
+ if (!(p->dev_flags[tindex] & DEVICE_PRESENT))
{
if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
{
- char *buffer;
-
+
p->dev_flags[tindex] |= DEVICE_PRESENT;
- if(cmd->use_sg)
- {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *)cmd->request_buffer;
- buffer = (char *)sg[0].address;
- }
- else
- {
- buffer = (char *)cmd->request_buffer;
- }
#define WIDE_INQUIRY_BITS 0x60
#define SYNC_INQUIRY_BITS 0x10
#define SCSI_VERSION_BITS 0x07
#define SCSI_DT_BIT 0x04
- if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
- (p->features & AHC_WIDE) )
- {
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
- }
- else
- {
- p->needwdtr &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- pause_sequencer(p);
- aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
- MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
- AHC_TRANS_GOAL |
- AHC_TRANS_CUR) );
- unpause_sequencer(p, FALSE);
- }
- if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
- p->transinfo[tindex].user_offset )
- {
- p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
- if (p->features & AHC_ULTRA2)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) {
+ char *buffer;
+
+ if(cmd->use_sg)
+ {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ buffer = (char *)sg[0].address;
+ }
+ else
+ {
+ buffer = (char *)cmd->request_buffer;
+ }
+
+
+ if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
+ (p->features & AHC_WIDE) )
+ {
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
+ p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
+ }
else
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
- if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
- (buffer[56] & SCSI_DT_BIT) ||
- (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
- (p->transinfo[tindex].user_period <= 9) &&
- (p->transinfo[tindex].user_options) )
{
- p->needppr |= (1<<tindex);
- p->needppr_copy |= (1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
p->needwdtr &= ~(1<<tindex);
p->needwdtr_copy &= ~(1<<tindex);
- p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ pause_sequencer(p);
+ aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
+ MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+ AHC_TRANS_GOAL |
+ AHC_TRANS_CUR) );
+ unpause_sequencer(p, FALSE);
+ }
+ if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+ p->transinfo[tindex].user_offset )
+ {
+ p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+ if (p->features & AHC_ULTRA2)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ else
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) ||
+ (buffer[56] & SCSI_DT_BIT) ||
+ (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+ (p->transinfo[tindex].user_period <= 9) &&
+ (p->transinfo[tindex].user_options) )
+ {
+ p->needppr |= (1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ }
+ else
+ {
+ p->needsdtr |= (1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ p->transinfo[tindex].goal_period =
+ MAX(10, p->transinfo[tindex].goal_period);
+ p->transinfo[tindex].goal_options = 0;
+ }
}
else
{
- p->needsdtr |= (1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- p->transinfo[tindex].goal_period =
- MAX(10, p->transinfo[tindex].goal_period);
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
p->transinfo[tindex].goal_options = 0;
}
- }
- else
- {
- p->needsdtr &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_period = 255;
- p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_options = 0;
- }
- /*
- * This is needed to work around a sequencer bug for now. Regardless
- * of the controller in use, if we have a Quantum drive, we need to
- * limit the speed to 80MByte/sec. As soon as I get a fixed version
- * of the sequencer, this code will get yanked.
- */
- if(!strncmp(buffer + 8, "QUANTUM", 7) &&
- p->transinfo[tindex].goal_options )
- {
- p->transinfo[tindex].goal_period =
- MAX(p->transinfo[tindex].goal_period, 10);
- p->transinfo[tindex].goal_options = 0;
- p->needppr &= ~(1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- }
- /*
- * Get the INQUIRY checksum. We use this on Ultra 160/m
- * and older devices both. It allows us to drop speed on any bus type
- * while at the same time giving us the needed domain validation for
- * Ultra 160/m
- *
- * Note: We only get the checksum and set the SCANNED bit if this is
- * one of our dtr commands. If we don't do this, then we end up
- * getting bad checksum results on the mid-level SCSI code's INQUIRY
- * commands.
- */
- if(p->dev_dtr_cmnd[tindex] == cmd) {
- unsigned int checksum = 0;
- int *ibuffer;
- int i=0;
-
- ibuffer = (int *)buffer;
- for( i = 0; i < (cmd->request_bufflen >> 2); i++)
- {
- checksum += ibuffer[i];
- }
- p->dev_checksum[tindex] = checksum;
- p->dev_flags[tindex] |= DEVICE_SCANNED;
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED;
p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
}
#undef WIDE_INQUIRY_BITS
#undef SCSI_DT_BIT
}
}
- else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+
+ if ((scb->flags & SCB_MSGOUT_BITS) != 0)
{
unsigned short mask;
int message_error = FALSE;
if (scb->flags & SCB_MSGOUT_WDTR)
{
- p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
}
if (scb->flags & SCB_MSGOUT_SDTR)
{
- p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
}
if (scb->flags & SCB_MSGOUT_PPR)
{
- p->dtr_pending &= ~mask;
if(message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
}
}
}
+
queue_depth = p->dev_temp_queue_depth[tindex];
if (queue_depth >= p->dev_active_cmds[tindex])
{
}
}
}
- if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
+ if (!(scb->tag_action))
+ {
+ aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
+ /* unbusy */ TRUE);
+ if (p->tagenable & (1<<tindex))
+ {
+ p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+ }
+ }
+ if(scb->flags & SCB_DTR_SCB)
{
- p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+ p->dtr_pending &= ~(1 << tindex);
}
p->dev_active_cmds[tindex]--;
p->activescbs--;
printk(INFO_LEAD "Aborting scb %d\n",
p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
found++;
+ /*
+ * Clear any residual information since the normal aic7xxx_done() path
+ * doesn't touch the residuals.
+ */
+ scb->hscb->residual_SG_segment_count = 0;
+ scb->hscb->residual_data_count[0] = 0;
+ scb->hscb->residual_data_count[1] = 0;
+ scb->hscb->residual_data_count[2] = 0;
aic7xxx_done(p, scb);
}
}
active_scb = aic_inb(p, SCBPTR);
if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+ {
printk(INFO_LEAD "Reset device, active_scb %d\n",
p->host_no, channel, target, lun, active_scb);
+ printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE "
+ "0x%x\n",
+ p->host_no, channel, target, lun, aic_inb(p, SCB_TAG),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, LASTPHASE));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+ p->host_no, channel, target, lun,
+ (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+ aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI));
+ printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+ p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
+ aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+ }
/*
* Deal with the busy target and linked next issues.
*/
if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
printk(INFO_LEAD "Cleaning up status information "
"and delayed_scbs.\n", p->host_no, channel, i, lun);
- p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
+ p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
if ( tag == SCB_LIST_NULL )
{
p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
- p->dev_expires[i] = jiffies + (4 * HZ);
+ p->dev_expires[i] = jiffies + (1 * HZ);
p->dev_timer_active |= (0x01 << i);
p->dev_last_queue_full_count[i] = 0;
p->dev_last_queue_full[i] = 0;
prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
}
}
- if ( j > (p->scb_data->maxscbs + 1) )
+ if ( j > (p->scb_data->numscbs + 1) )
{
if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
printk(WARN_LEAD "Yikes!! There's a loop in the "
prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
}
}
- if ( j > (p->scb_data->maxscbs + 1) )
+ if ( j > (p->scb_data->numscbs + 1) )
{
if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
printk(WARN_LEAD "Yikes!! There's a loop in the "
if (actual < cmd->underflow)
{
if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ {
printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
"count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
(cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
hscb->residual_SG_segment_count);
+ printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
+ hscb->target_status);
+ }
+ /*
+ * In 2.4, only send back the residual information, don't flag this
+ * as an error. Before 2.4 we had to flag this as an error because
+ * the mid layer didn't check residual data counts to see if the
+ * command needs retried.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ cmd->resid = scb->sg_length - actual;
+#else
aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+#endif
aic7xxx_status(cmd) = hscb->target_status;
}
}
*/
p->needwdtr &= ~target_mask;
p->needwdtr_copy &= ~target_mask;
- p->dtr_pending &= ~target_mask;
scb->flags &= ~SCB_MSGOUT_BITS;
aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
(AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
*/
p->needsdtr &= ~target_mask;
p->needsdtr_copy &= ~target_mask;
- p->dtr_pending &= ~target_mask;
- scb->flags &= ~SCB_MSGOUT_SDTR;
+ scb->flags &= ~SCB_MSGOUT_BITS;
aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
(AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
aic7xxx_error(cmd) = DID_OK;
break;
} /* first time sense, no errors */
+ printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning "
+ "an error.\n", p->host_no, CTL_OF_SCB(scb));
aic7xxx_error(cmd) = DID_ERROR;
scb->flags &= ~SCB_SENSE;
break;
printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n",
(aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
scb->sg_length, scb->sg_count);
- for (i = 0; i < scb->sg_count; i++)
+ printk(KERN_WARNING " Raw SCSI Command: 0x");
+ for (i = 0; i < scb->hscb->SCSI_cmd_length; i++)
+ {
+ printk("%02x ", scb->cmd->cmnd[i]);
+ }
+ printk("\n");
+ if(aic7xxx_verbose > 0xffff)
{
- printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n",
+ for (i = 0; i < scb->sg_count; i++)
+ {
+ printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n",
i,
le32_to_cpu(scb->sg_list[i].address),
le32_to_cpu(scb->sg_list[i].length) );
+ }
}
aic7xxx_error(scb->cmd) = DID_ERROR;
}
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;
+ unsigned int native_addr, native_length, sg_addr;
int i;
if(scb_index > p->scb_data->numscbs)
scb->flags, (unsigned long)scb->cmd);
break;
}
+ if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data "
+ "pointer.\n", p->host_no, CTL_OF_SCB(scb));
/*
* We have a valid scb to use on this WIDE_RESIDUE message, so
*/
cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
(aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+ sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) |
+ (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 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) << 16);
- index = scb->sg_count - (resid_sgcnt + 1);
+ index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1);
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 resid_dcnt == native_length, then we just loaded this SG
+ * segment and we need to back it up one...
*/
- if(cur_addr < native_addr ||
- cur_addr > (native_addr + native_length + 1))
- {
- 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));
- printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n",
- p->host_no, CTL_OF_SCB(scb),
- cur_addr, resid_dcnt);
- break;
- }
-
- if( (resid_sgcnt == 0) &&
- ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
- {
- /*
- * We are at the end of the transfer and this is about a byte
- * we ignored already (because the sequencer knew this was
- * the last segment and set the adapter to ignore any wide
- * residue bytes that might come through, which is only done
- * on the last scatter gather segment of transfers).
- */
- break;
- }
- else if(cur_addr == native_addr)
+ if(resid_dcnt == native_length)
{
- /*
- * 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(index == 0)
{
- printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
- "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+ /*
+ * Oops, this isn't right, we can't back up to before the
+ * beginning. This must be a bogus message, ignore it.
+ */
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);
+ resid_dcnt = 1;
+ resid_sgcnt += 1;
+ native_addr = le32_to_cpu(scb->sg_list[index - 1].address);
+ native_length = le32_to_cpu(scb->sg_list[index - 1].length);
+ cur_addr = native_addr + (native_length - 1);
+ sg_addr -= sizeof(struct hw_scatterlist);
}
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.
+ * resid_dcnt != native_length, so we are in the middle of a SG
+ * element. Back it up one byte and leave the rest alone.
*/
- 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);
+ resid_dcnt += 1;
+ cur_addr -= 1;
}
+
+ /*
+ * Output the new addresses and counts to the right places on the
+ * card.
+ */
+ aic_outb(p, resid_sgcnt, SG_COUNT);
+ aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+ aic_outb(p, sg_addr & 0xff, SG_COUNT + 1);
+ aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2);
+ aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3);
+ aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4);
+ 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);
+
/*
- * 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.
+ * The sequencer actually wants to find the new address
+ * in the SHADDR register set. On the Ultra2 and later controllers
+ * this register set is readonly. In order to get the right number
+ * into the register, you actually have to enter it in HADDR and then
+ * use the PRELOADEN bit of DFCNTRL to drop it through from the
+ * HADDR register to the SHADDR register. On non-Ultra2 controllers,
+ * we simply write it direct.
*/
if(p->features & AHC_ULTRA2)
{
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- i=0;
+ /*
+ * We might as well be accurate and drop both the resid_dcnt and
+ * cur_addr into HCNT and HADDR and have both of them drop
+ * through to the shadow layer together.
+ */
+ 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);
+ aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL);
udelay(1);
- while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
- {
- udelay(1);
- }
aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
i=0;
- udelay(1);
while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
{
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);
}
break;
-
-#if AIC7XXX_NOT_YET
- case TRACEPOINT:
- {
- printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
- channel, target, lun);
+ case SEQ_SG_FIXUP:
+ {
+ unsigned char scb_index, tmp;
+ int sg_addr, sg_length;
+
+ scb_index = aic_inb(p, SCB_TAG);
+
+ if(scb_index > p->scb_data->numscbs)
+ {
+ printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n",
+ p->host_no, -1, -1, -1);
+ printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+ "0x%x\n", p->host_no, -1, -1, -1,
+ aic_inb(p, SCSISIGI),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+ p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR),
+ aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+ aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+ /*
+ * XXX: Add error handling here
+ */
+ break;
}
- break;
+ scb = p->scb_data->scb_array[scb_index];
+ if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
+ "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb),
+ scb->flags, (unsigned int)scb->cmd);
+ printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+ "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+ aic_inb(p, SCSISIGI),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR),
+ aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+ aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+ break;
+ }
+ if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no,
+ CTL_OF_SCB(scb));
+ /*
+ * Advance the SG pointer to the next element in the list
+ */
+ tmp = aic_inb(p, SG_NEXT);
+ tmp += SG_SIZEOF;
+ aic_outb(p, tmp, SG_NEXT);
+ if( tmp < SG_SIZEOF )
+ aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1);
+ tmp = aic_inb(p, SG_COUNT) - 1;
+ aic_outb(p, tmp, SG_COUNT);
+ sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address);
+ sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length);
+ /*
+ * Now stuff the element we just advanced past down onto the
+ * card so it can be stored in the residual area.
+ */
+ aic_outb(p, sg_addr & 0xff, HADDR);
+ aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3);
+ aic_outb(p, sg_length & 0xff, HCNT);
+ aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1);
+ aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2);
+ aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR);
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ while(aic_inb(p, SSTAT0) & SDONE) udelay(1);
+ while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL);
+ }
+ break;
+#if AIC7XXX_NOT_YET
case TRACEPOINT2:
{
printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
unsigned char target_scsirate, tindex;
unsigned short target_mask;
unsigned char target, channel, lun;
+ unsigned char bus_width, new_bus_width;
+ unsigned char trans_options, new_trans_options;
+ unsigned int period, new_period, offset, new_offset, maxsync;
+ struct aic7xxx_syncrate *syncrate;
target = scb->cmd->target;
channel = scb->cmd->channel;
reject = TRUE;
}
+ /*
+ * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+ * using the SDTR messages. We need the PPR messages to enable the
+ * higher speeds that include things like Dual Edge clocking.
+ */
+ if (p->features & AHC_ULTRA2)
+ {
+ if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+ !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+ {
+ if (p->features & AHC_ULTRA3)
+ maxsync = AHC_SYNCRATE_ULTRA3;
+ else
+ maxsync = AHC_SYNCRATE_ULTRA2;
+ }
+ else
+ {
+ maxsync = AHC_SYNCRATE_ULTRA;
+ }
+ }
+ else if (p->features & AHC_ULTRA)
+ {
+ maxsync = AHC_SYNCRATE_ULTRA;
+ }
+ else
+ {
+ maxsync = AHC_SYNCRATE_FAST;
+ }
+
/*
* Just accept the length byte outright and perform
* more checking once we know the message type.
{
case MSG_EXT_SDTR:
{
- unsigned int period, offset;
- unsigned char maxsync, saved_offset, options;
- struct aic7xxx_syncrate *syncrate;
if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
{
break;
}
- period = p->msg_buf[3];
- saved_offset = offset = p->msg_buf[4];
- options = 0;
+ period = new_period = p->msg_buf[3];
+ offset = new_offset = p->msg_buf[4];
+ trans_options = new_trans_options = 0;
+ bus_width = new_bus_width = target_scsirate & WIDEXFER;
/*
- * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
- * using the SDTR messages. We need the PPR messages to enable the
- * higher speeds that include things like Dual Edge clocking.
+ * If our current max syncrate is in the Ultra3 range, bump it back
+ * down to Ultra2 since we can't negotiate DT transfers using SDTR
*/
- if (p->features & AHC_ULTRA2)
- {
- if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
- !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
- {
- maxsync = AHC_SYNCRATE_ULTRA2;
- }
- else
- {
- maxsync = AHC_SYNCRATE_ULTRA;
- }
- }
- else if (p->features & AHC_ULTRA)
- {
- maxsync = AHC_SYNCRATE_ULTRA;
- }
- else
- {
- maxsync = AHC_SYNCRATE_FAST;
- }
+ if(maxsync == AHC_SYNCRATE_ULTRA3)
+ maxsync = AHC_SYNCRATE_ULTRA2;
+
/*
* We might have a device that is starting negotiation with us
* before we can start up negotiation with it....be prepared to
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
{
- if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
- !(p->needsdtr_copy & target_mask) &&
- (p->transinfo[tindex].user_offset) )
+ if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
{
/*
- * Not only is the device starting this up, but it also hasn't
- * been scanned yet, so this would likely be our TUR or our
- * INQUIRY command at scan time, so we need to use the
- * settings from the SEEPROM if they existed. Of course, even
- * if we didn't find a SEEPROM, we stuffed default values into
- * the user settings anyway, so use those in all cases.
+ * We shouldn't get here unless this is a narrow drive, wide
+ * devices should trigger this same section of code in the WDTR
+ * handler first instead.
*/
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
- if(p->features & AHC_ULTRA2)
- {
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- }
- else if (p->transinfo[tindex].cur_width)
+ p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+ p->transinfo[tindex].goal_options = 0;
+ if(p->transinfo[tindex].user_offset)
{
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ p->needsdtr_copy |= target_mask;
+ p->transinfo[tindex].goal_period =
+ MAX(10,p->transinfo[tindex].user_period);
+ if(p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
}
else
{
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ p->needsdtr_copy &= ~target_mask;
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
}
- p->needsdtr_copy |= target_mask;
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+ }
+ else if ((p->needsdtr_copy & target_mask) == 0)
+ {
+ /*
+ * This is a preemptive message from the target, we've already
+ * scanned this target and set our options for it, and we
+ * don't need a WDTR with this target (for whatever reason),
+ * so reject this incoming WDTR
+ */
+ reject = TRUE;
+ break;
}
+
+ /* The device is sending this message first and we have to reply */
+ reply = TRUE;
+
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Received pre-emptive SDTR message from "
"target.\n", p->host_no, CTL_OF_SCB(scb));
}
- if ( !p->transinfo[tindex].goal_offset )
- period = 255;
- if ( p->transinfo[tindex].goal_period > period )
- period = p->transinfo[tindex].goal_period;
+ /*
+ * Validate the values the device passed to us against our SEEPROM
+ * settings. We don't have to do this if we aren't replying since
+ * the device isn't allowed to send values greater than the ones
+ * we first sent to it.
+ */
+ new_period = MAX(period, p->transinfo[tindex].goal_period);
+ new_offset = MIN(offset, p->transinfo[tindex].goal_offset);
}
-
- syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
- aic7xxx_validate_offset(p, syncrate, &offset,
- target_scsirate & WIDEXFER);
- aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+
+ /*
+ * Use our new_period, new_offset, bus_width, and card options
+ * to determine the actual syncrate settings
+ */
+ syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+ &trans_options);
+ aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width);
/*
- * Did we drop to async? Or are we sending a reply? If we are,
- * then we have to make sure that the reply value reflects the proper
- * settings so we need to set the goal values according to what
- * we need to send.
+ * Did we drop to async? If so, send a reply regardless of whether
+ * or not we initiated this negotiation.
*/
- if ( (offset != saved_offset) ||
- ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
- (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
+ if ((new_offset == 0) && (new_offset != offset))
{
- aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
- options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ p->needsdtr_copy &= ~target_mask;
+ reply = TRUE;
}
/*
- * Did we start this, if not, or if we went to low and had to
+ * Did we start this, if not, or if we went too low and had to
* go async, then send an SDTR back to the target
*/
- p->needsdtr &= ~target_mask;
- p->dtr_pending &= ~target_mask;
- if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
- (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
- (offset != saved_offset) )
+ if(reply)
{
- reply = TRUE;
- p->dtr_pending |= target_mask;
+ /* when sending a reply, make sure that the goal settings are
+ * updated along with current and active since the code that
+ * will actually build the message for the sequencer uses the
+ * goal settings as its guidelines.
+ */
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, trans_options,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_SDTR;
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
}
+ else
+ {
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, trans_options,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ p->needsdtr &= ~target_mask;
+ }
done = TRUE;
break;
}
case MSG_EXT_WDTR:
{
- unsigned char bus_width;
if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
{
break;
}
- bus_width = p->msg_buf[3];
+ bus_width = new_bus_width = p->msg_buf[3];
+
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
(SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
{
} /* We fall through on purpose */
case MSG_EXT_WDTR_BUS_8_BIT:
{
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
p->needwdtr_copy &= ~target_mask;
break;
}
break;
}
}
- p->dtr_pending &= ~target_mask;
p->needwdtr &= ~target_mask;
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
}
else
{
- if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+ if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
{
/*
* Well, we now know the WDTR and SYNC caps of this device since
* it contacted us first, mark it as such and copy the user stuff
* over to the goal stuff.
*/
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
+ if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width )
+ {
+ p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+ p->needwdtr_copy |= target_mask;
+ }
+
+ /*
+ * Devices that support DT transfers don't start WDTR requests
+ */
+ p->transinfo[tindex].goal_options = 0;
+
if(p->transinfo[tindex].user_offset)
{
+ p->needsdtr_copy |= target_mask;
+ p->transinfo[tindex].goal_period =
+ MAX(10,p->transinfo[tindex].user_period);
if(p->features & AHC_ULTRA2)
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
}
- else if( p->transinfo[tindex].user_width &&
- (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
- p->features & AHC_WIDE )
+ else if( p->transinfo[tindex].goal_width )
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
}
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
}
+ } else {
+ p->needsdtr_copy &= ~target_mask;
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
}
- p->transinfo[tindex].goal_width =
- p->transinfo[tindex].user_width;
- p->needwdtr_copy |= target_mask;
- p->needsdtr_copy |= target_mask;
+
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+ }
+ else if ((p->needwdtr_copy & target_mask) == 0)
+ {
+ /*
+ * This is a preemptive message from the target, we've already
+ * scanned this target and set our options for it, and we
+ * don't need a WDTR with this target (for whatever reason),
+ * so reject this incoming WDTR
+ */
+ reject = TRUE;
+ break;
}
+
+ /* The device is sending this message first and we have to reply */
+ reply = TRUE;
+
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Received pre-emptive WDTR message from "
}
switch(bus_width)
{
- default:
+ case MSG_EXT_WDTR_BUS_16_BIT:
{
if ( (p->features & AHC_WIDE) &&
(p->transinfo[tindex].goal_width ==
MSG_EXT_WDTR_BUS_16_BIT) )
{
- bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
break;
}
} /* Fall through if we aren't a wide card */
+ default:
case MSG_EXT_WDTR_BUS_8_BIT:
{
p->needwdtr_copy &= ~target_mask;
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
break;
}
}
- reply = TRUE;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_WDTR;
p->needwdtr &= ~target_mask;
- p->dtr_pending |= target_mask;
+ if((p->dtr_pending & target_mask) == 0)
+ {
+ /* there is no other command with SCB_DTR_SCB already set that will
+ * trigger the release of the dtr_pending bit. Both set the bit
+ * and set scb->flags |= SCB_DTR_SCB
+ */
+ p->dtr_pending |= target_mask;
+ scb->flags |= SCB_DTR_SCB;
+ }
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ /* when sending a reply, make sure that the goal settings are
+ * updated along with current and active since the code that
+ * will actually build the message for the sequencer uses the
+ * goal settings as its guidelines.
+ */
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
}
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
/*
* By virtue of the SCSI spec, a WDTR message negates any existing
}
case MSG_EXT_PPR:
{
- unsigned char bus_width, trans_options, new_trans_options;
- unsigned int period, offset;
- unsigned char maxsync, saved_offset;
- struct aic7xxx_syncrate *syncrate;
if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
{
break;
}
- period = p->msg_buf[3];
- offset = saved_offset = p->msg_buf[5];
- bus_width = p->msg_buf[6];
+ period = new_period = p->msg_buf[3];
+ offset = new_offset = p->msg_buf[5];
+ bus_width = new_bus_width = p->msg_buf[6];
trans_options = new_trans_options = p->msg_buf[7] & 0xf;
if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
trans_options);
}
- if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
- !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
- {
- if(p->features & AHC_ULTRA3)
- {
- maxsync = AHC_SYNCRATE_ULTRA3;
- }
- else
- {
- maxsync = AHC_SYNCRATE_ULTRA2;
- }
- }
- else
- {
- maxsync = AHC_SYNCRATE_ULTRA;
- }
/*
* We might have a device that is starting negotiation with us
* before we can start up negotiation with it....be prepared to
*/
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
- {
- reply = TRUE;
- scb->flags &= ~SCB_MSGOUT_BITS;
- scb->flags |= SCB_MSGOUT_PPR;
- p->dev_flags[tindex] |= DEVICE_SCSI_3;
- if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+ {
+ /* Have we scanned the device yet? */
+ if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
{
+ /* The device is electing to use PPR messages, so we will too until
+ * we know better */
+ p->needppr |= target_mask;
+ p->needppr_copy |= target_mask;
+ p->needsdtr &= ~target_mask;
+ p->needsdtr_copy &= ~target_mask;
+ p->needwdtr &= ~target_mask;
+ p->needwdtr_copy &= ~target_mask;
+
+ /* We know the device is SCSI-3 compliant due to PPR */
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+
/*
* Not only is the device starting this up, but it also hasn't
* been scanned yet, so this would likely be our TUR or our
* if we didn't find a SEEPROM, we stuffed default values into
* the user settings anyway, so use those in all cases.
*/
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_width =
+ p->transinfo[tindex].user_width;
if(p->transinfo[tindex].user_offset)
{
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options =
+ p->transinfo[tindex].user_options;
if(p->features & AHC_ULTRA2)
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
}
- else if( p->transinfo[tindex].user_width &&
+ else if( p->transinfo[tindex].goal_width &&
(bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
p->features & AHC_WIDE )
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
}
}
- p->transinfo[tindex].goal_width =
- p->transinfo[tindex].user_width;
- p->transinfo[tindex].goal_options =
- p->transinfo[tindex].user_options;
+ else
+ {
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+ }
+ else if ((p->needppr_copy & target_mask) == 0)
+ {
+ /*
+ * This is a preemptive message from the target, we've already
+ * scanned this target and set our options for it, and we
+ * don't need a PPR with this target (for whatever reason),
+ * so reject this incoming PPR
+ */
+ reject = TRUE;
+ break;
}
+
+ /* The device is sending this message first and we have to reply */
+ reply = TRUE;
+
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Received pre-emptive PPR message from "
"target.\n", p->host_no, CTL_OF_SCB(scb));
}
- if ( !p->transinfo[tindex].goal_offset )
- period = 255;
- if ( p->transinfo[tindex].goal_period > period )
- period = p->transinfo[tindex].goal_period;
- if ( p->transinfo[tindex].goal_options == 0 )
- new_trans_options = 0;
- switch(bus_width)
+
+ }
+
+ switch(bus_width)
+ {
+ case MSG_EXT_WDTR_BUS_16_BIT:
{
- default:
+ if ( (p->transinfo[tindex].goal_width ==
+ MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE)
{
- if ( (p->features & AHC_WIDE) &&
- (p->transinfo[tindex].goal_width ==
- MSG_EXT_WDTR_BUS_16_BIT) )
- {
- bus_width = MSG_EXT_WDTR_BUS_16_BIT;
- break;
- }
- } /* Fall through if we aren't a wide card */
- case MSG_EXT_WDTR_BUS_8_BIT:
- {
- p->needwdtr_copy &= ~target_mask;
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_GOAL|AHC_TRANS_QUITE);
break;
}
}
- if ( (p->transinfo[tindex].goal_period > 9) ||
- (p->transinfo[tindex].goal_options == 0) )
+ default:
{
- scb->flags &= ~SCB_MSGOUT_BITS;
- reject = TRUE;
- reply = FALSE;
- p->needppr &= ~(1 << tindex);
- p->needppr_copy &= ~(1 << tindex);
- if ( p->transinfo[tindex].goal_offset )
- {
- p->needsdtr |= (1 << tindex);
- p->needsdtr_copy |= (1 << tindex);
- }
- if ( p->transinfo[tindex].goal_width )
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+ ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+ (aic7xxx_verbose > 0xffff)) )
{
- p->needwdtr |= (1 << tindex);
- p->needwdtr_copy |= (1 << tindex);
+ reply = TRUE;
+ printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+ p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
}
+ } /* We fall through on purpose */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ {
+ /*
+ * According to the spec, if we aren't wide, we also can't be
+ * Dual Edge so clear the options byte
+ */
+ new_trans_options = 0;
+ new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ break;
}
}
+
+ if(reply)
+ {
+ /* when sending a reply, make sure that the goal settings are
+ * updated along with current and active since the code that
+ * will actually build the message for the sequencer uses the
+ * goal settings as its guidelines.
+ */
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+ &new_trans_options);
+ aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, new_trans_options,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ }
else
{
- switch(bus_width)
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+ &new_trans_options);
+ aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, new_trans_options,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ }
+
+ /*
+ * As it turns out, if we don't *have* to have PPR messages, then
+ * configure ourselves not to use them since that makes some
+ * external drive chassis work (those chassis can't parse PPR
+ * messages and they mangle the SCSI bus until you send a WDTR
+ * and SDTR that they can understand).
+ */
+ if(new_trans_options == 0)
+ {
+ p->needppr &= ~target_mask;
+ p->needppr_copy &= ~target_mask;
+ if(new_offset)
{
- default:
- {
- reject = TRUE;
- if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
- (aic7xxx_verbose > 0xffff)) )
- {
- printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
- p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
- }
- } /* We fall through on purpose */
- case MSG_EXT_WDTR_BUS_8_BIT:
- {
- /*
- * According to the spec, if we aren't wide, we also can't be
- * Dual Edge so clear the options byte
- */
- new_trans_options = 0;
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- break;
- }
- case MSG_EXT_WDTR_BUS_16_BIT:
- {
- break;
- }
+ p->needsdtr |= target_mask;
+ p->needsdtr_copy |= target_mask;
+ }
+ if (new_bus_width)
+ {
+ p->needwdtr |= target_mask;
+ p->needwdtr_copy |= target_mask;
}
}
- if ( !reject )
+ if((new_offset == 0) && (offset != 0))
{
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
- syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
- &new_trans_options);
- aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
- aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, new_trans_options,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ /*
+ * Oops, the syncrate went to low for this card and we fell off
+ * to async (should never happen with a device that uses PPR
+ * messages, but have to be complete)
+ */
+ reply = TRUE;
}
- p->dtr_pending &= ~target_mask;
- p->needppr &= ~target_mask;
if(reply)
{
- p->dtr_pending |= target_mask;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_PPR;
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
}
+ else
+ {
+ p->needppr &= ~target_mask;
+ }
done = TRUE;
break;
}
printerror = 0;
}
}
- if ( (scb != NULL) &&
- (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+ if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) )
{
/*
- * This might be a SCSI-3 device that is dropping the bus due to
- * errors and signalling that we should reduce the transfer speed.
- * All we have to do is complete this command (since it's a negotiation
- * command already) and the checksum routine should flag an error and
- * reduce the speed setting and renegotiate. We call the reset routing
- * just to clean out the hardware from this scb.
+ * Hmmm...error during a negotiation command. Either we have a
+ * borken bus, or the device doesn't like our negotiation message.
+ * Since we check the INQUIRY data of a device before sending it
+ * negotiation messages, assume the bus is borken for whatever
+ * reason. Complete the command.
*/
printerror = 0;
aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
cmd->result = 0;
scb = NULL;
}
- else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
- {
- /*
- * Turn off the needsdtr, needwdtr, and needppr bits since this device
- * doesn't seem to exist.
- */
- p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
- }
}
/*
* Keep the sequencer from trying to restart any selections
}
}
else if( (lastphase == P_MESGOUT) &&
- (cmd == p->dev_dtr_cmnd[tindex]) &&
(scb->flags & SCB_MSGOUT_PPR) )
{
/*
aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
p->transinfo[tindex].goal_options = 0;
- p->dtr_pending &= ~(1 << tindex);
scb->flags &= ~SCB_MSGOUT_BITS;
if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
}
scb = NULL;
}
- else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
- {
- struct aic7xxx_syncrate *syncrate;
- unsigned int period = p->transinfo[tindex].cur_period;
- unsigned char options = p->transinfo[tindex].cur_options;
- /*
- * oops, we had a failure, lower the transfer rate and try again. It's
- * worth noting here that it might be wise to also check for typical
- * wide setting on narrow cable type problems and try disabling wide
- * instead of slowing down if those exist. That's hard to do with simple
- * checksums though.
- */
- printk(WARN_LEAD "Parity error during %s phase.\n",
- p->host_no, CTL_OF_SCB(scb), phase);
- if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
- {
- syncrate++;
- if( (syncrate->rate[0] != NULL) &&
- (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
- {
- p->transinfo[tindex].goal_period = syncrate->period;
- if( p->transinfo[tindex].goal_period > 9 )
- {
- p->transinfo[tindex].goal_options = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- if (p->transinfo[tindex].goal_width)
- {
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- }
- }
- }
- else if (p->transinfo[tindex].goal_width)
- {
- p->transinfo[tindex].goal_width = 0;
- p->needwdtr &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_options =
- p->transinfo[tindex].user_options;
- if( p->transinfo[tindex].goal_period <= 9 )
- {
- p->needppr |= (1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needppr_copy |= (1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- }
- else
- {
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- }
- }
- else
- {
- p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 255;
- p->transinfo[tindex].goal_options = 0;
- p->transinfo[tindex].goal_width = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needwdtr &= ~(1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- }
- }
- p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
- }
- else
- {
- p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
- }
/*
* We've set the hardware to assert ATN if we get a parity
else if (scb->flags & SCB_SENSE)
{
char *buffer = &scb->cmd->sense_buffer[0];
- if (scb->cmd == p->dev_dtr_cmnd[tindex])
- {
- struct aic7xxx_scb *old_scb;
- /*
- * We have valid sense data, send it back immediately.
- */
- old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
- *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
- old_scb->hscb->target_status = scb->hscb->target_status;
- old_scb->cmd->result = scb->hscb->target_status;
- old_scb->cmd->result |= (DID_ERROR << 16);
- aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
- scbq_remove(&p->waiting_scbs, old_scb);
- scbq_remove(&p->delayed_scbs[tindex], old_scb);
- scb->cmd->next = NULL;
- aic7xxx_done(p, scb);
- aic7xxx_done(p, old_scb);
- continue;
- }
- else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+
+ if (buffer[12] == 0x47 || buffer[12] == 0x54)
{
/*
- * SCSI errors, run domain validation and re-run negotiation
- */
- p->needdv |= (1<<tindex);
- /*
- * Signal that we need to re-negotiate things, this also gets us our
- * INQUIRY command to re-checksum off of.
+ * Signal that we need to re-negotiate things.
*/
p->needppr |= (p->needppr_copy & (1<<tindex));
p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
case BUSY:
scb->hscb->target_status = 0;
scb->cmd->result = 0;
+ scb->hscb->residual_SG_segment_count = 0;
+ scb->hscb->residual_data_count[0] = 0;
+ scb->hscb->residual_data_count[1] = 0;
+ scb->hscb->residual_data_count[2] = 0;
aic7xxx_error(scb->cmd) = DID_OK;
+ aic7xxx_status(scb->cmd) = 0;
+ /*
+ * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
+ * this command on a timer and allowing us to retry it. Here, we
+ * just 0 out a few values so that they don't carry through to when
+ * the command finally does complete.
+ */
break;
default:
cmd = scb->cmd;
if(!p)
return;
spin_lock_irqsave(&io_request_lock, cpu_flags);
- if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
- {
- spin_unlock_irqrestore(&io_request_lock, cpu_flags);
- return;
- }
+ p->flags |= AHC_IN_ISR;
do
{
aic7xxx_isr(irq, dev_id, regs);
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
- clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
+ p->flags &= ~AHC_IN_ISR;
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
}
/*
* In the future, we may call this function as a last resort for
- * error handling. Let's be nice and not do any unecessary delays.
+ * error handling. Let's be nice and not do any unnecessary delays.
*/
wait = 1000; /* 1 msec (1000 * 1 msec) */
while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
kfree(p->scb_data);
}
- /*
- * Free any alloced Scsi_Cmnd structures that might be around for
- * negotiation purposes....
- */
- for (i = 0; i < MAX_TARGETS; i++)
- {
- if(p->dev_dtr_cmnd[i])
- {
- if(p->dev_dtr_cmnd[i]->request_buffer)
- {
- kfree(p->dev_dtr_cmnd[i]->request_buffer);
- }
- kfree(p->dev_dtr_cmnd[i]);
- }
- }
-
pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
}
}
aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
- p->needppr = p->needppr_copy = p->needdv = 0;
+ p->needppr = p->needppr_copy = 0;
p->needwdtr = p->needwdtr_copy;
p->needsdtr = p->needsdtr_copy;
p->dtr_pending = 0;
}
}
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_configure_bugs
+ *
+ * Description:
+ * Take the card passed in and set the appropriate bug flags based upon
+ * the card model. Also make any changes needed to device registers or
+ * PCI registers while we are here.
+ *-F*************************************************************************/
+static void
+aic7xxx_configure_bugs(struct aic7xxx_host *p)
+{
+ unsigned short tmp_word;
+
+ switch(p->chip & AHC_CHIPID_MASK)
+ {
+ case AHC_AIC7860:
+ p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+ /* fall through */
+ case AHC_AIC7850:
+ case AHC_AIC7870:
+ p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+ break;
+ case AHC_AIC7880:
+ p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+ AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+ break;
+ case AHC_AIC7890:
+ p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
+ break;
+ case AHC_AIC7892:
+ p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+ break;
+ case AHC_AIC7895:
+ p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+ AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+ break;
+ case AHC_AIC7896:
+ p->bugs |= AHC_BUG_CACHETHEN_DIS;
+ break;
+ case AHC_AIC7899:
+ p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+ break;
+ default:
+ /* Nothing to do */
+ break;
+ }
+
+ /*
+ * Now handle the bugs that require PCI register or card register tweaks
+ */
+ pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
+ if(p->bugs & AHC_BUG_PCI_MWI)
+ {
+ tmp_word &= ~PCI_COMMAND_INVALIDATE;
+ }
+ else
+ {
+ tmp_word |= PCI_COMMAND_INVALIDATE;
+ }
+ pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
+
+ if(p->bugs & AHC_BUG_CACHETHEN)
+ {
+ aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
+ }
+ else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
+ {
+ aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
+ }
+
+ return;
+}
+
+
/*+F*************************************************************************
* Function:
* aic7xxx_detect
aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
}
+ /*
+ * Call our function to fixup any bugs that exist on this chipset.
+ * This may muck with PCI settings and other device settings, so
+ * make sure it's after all the other PCI and device register
+ * tweaks so it can back out bad settings on specific broken cards.
+ */
+ aic7xxx_configure_bugs(temp_p);
+
if ( list_p == NULL )
{
list_p = current_p = temp_p;
(temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
}
+ /*
+ * All the 7770 based chipsets have this bug
+ */
+ temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
+
/*
* Set the FIFO threshold and the bus off time.
*/
return (found);
}
-static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
- Scsi_Cmnd *old_cmd, int tindex);
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_allocate_negotiation_command
- *
- * Description:
- * allocate the actual command struct and fill in the gaps...
- *-F*************************************************************************/
-static Scsi_Cmnd *
-aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
- Scsi_Cmnd *old_cmd, int tindex)
-{
- Scsi_Cmnd *cmd;
- char *buffer;
-
- if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
- {
- return(NULL);
- }
- if (!(buffer = kmalloc(256, GFP_ATOMIC)))
- {
- kfree(p->dev_dtr_cmnd[tindex]);
- p->dev_dtr_cmnd[tindex] = NULL;
- return(NULL);
- }
- cmd = p->dev_dtr_cmnd[tindex];
- memset(cmd, 0, sizeof(Scsi_Cmnd));
- memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
- memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
- memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
- cmd->lun = 0;
- cmd->request_bufflen = 255;
- cmd->request_buffer = buffer;
- cmd->sc_data_direction = SCSI_DATA_READ;
- cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
- cmd->bufflen = 0;
- cmd->buffer = NULL;
- cmd->underflow = 0;
- cmd->cmd_len = 6;
- cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
- cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
- cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
- cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
- cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
- cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
- return(cmd);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_negotiation_complete
- *
- * Description:
- * Handle completion events for our Negotiation commands. Clear out the
- * struct and get it ready for its next use.
- *-F*************************************************************************/
-static void
-aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
-{
- unsigned int checksum;
- int i;
- int *ibuffer;
- struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
- int tindex = TARGET_INDEX(cmd);
- struct aic7xxx_syncrate *syncrate;
-
- /*
- * perform our minimalistic domain validation
- */
- if(p->dev_flags[tindex] & DEVICE_SCANNED)
- {
- ibuffer = (int *)cmd->request_buffer;
- checksum = 0;
- for(i = 0; i < (cmd->request_bufflen >> 2); i++)
- {
- checksum += ibuffer[i];
- }
- if( (checksum != p->dev_checksum[tindex]) &&
- (p->transinfo[tindex].cur_offset != 0) )
- {
- unsigned int period = p->transinfo[tindex].cur_period;
- unsigned char options = p->transinfo[tindex].cur_options;
-
- if (p->needdv & (1<<tindex))
- {
- /*
- * oops, we had a failure, lower the transfer rate and try again. It's
- * worth noting here that it might be wise to also check for typical
- * wide setting on narrow cable type problems and try disabling wide
- * instead of slowing down if those exist. That's hard to do with simple
- * checksums though.
- */
- 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));
- }
- if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
- {
- syncrate++;
- if( (syncrate->rate[0] != NULL) &&
- (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
- {
- p->transinfo[tindex].goal_period = syncrate->period;
- if( p->transinfo[tindex].goal_period > 9 )
- {
- p->transinfo[tindex].goal_options = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- if (p->transinfo[tindex].goal_width)
- {
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- }
- }
- }
- else if (p->transinfo[tindex].goal_width)
- {
- p->transinfo[tindex].goal_width = 0;
- p->needwdtr &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_options =
- p->transinfo[tindex].user_options;
- if( p->transinfo[tindex].goal_period <= 9 )
- {
- p->needppr |= (1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needppr_copy |= (1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- }
- else
- {
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- }
- }
- else
- {
- p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 255;
- p->transinfo[tindex].goal_options = 0;
- p->transinfo[tindex].goal_width = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needwdtr &= ~(1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- }
- }
- p->needdv &= ~(1<<tindex);
- }
- else
- {
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
- {
- printk(INFO_LEAD "Performing Domain validation.\n",
- p->host_no, CTL_OF_CMD(cmd));
- }
- /*
- * Update the checksum in case the INQUIRY data has changed, maybe
- * in relation to a change in the mode pages, or whatever.
- */
- p->dev_checksum[tindex] = checksum;
- /*
- * Signal that we are trying out the domain validation
- */
- p->needdv |= (1<<tindex);
- /*
- * Signal that we need to re-negotiate things, this also gets us our
- * INQUIRY command to re-checksum off of.
- */
- p->needppr |= (p->needppr_copy & (1<<tindex));
- p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
- p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
- }
- }
- else
- {
- if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->needdv & (1<<tindex)) )
- {
- printk(INFO_LEAD "Successfully completed Domain validation.\n",
- p->host_no, CTL_OF_CMD(cmd));
- }
- /*
- * We successfully did our checksum, so don't leave the needdv flag set
- * in case we might have set it last time through.
- */
- p->needdv &= ~(1<<tindex);
- }
- }
-
- p->dtr_pending &= ~(0x01 << tindex);
- /*
- * This looks recursive in the extreme, but if this was a WDTR negotiation
- * and we didn't follow up with SDTR yet, then this will get it started.
- * For all other cases, this should work out to be a no-op, unless we are
- * doing domain validation and happen to need a new negotiation command.
- *
- * In case we don't want this to go any further, the cmdcmplt interrupt
- * handler will NULL out the cmd->next entry so that the real SCSI command
- * can be sent back to the mid layer code with SENSE data intact. We'll
- * finish things up when the cmd gets sent back down to us, so no worries.
- */
- if(cmd->next)
- {
- aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
- }
- return;
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_build_negotiation_command
- *
- * Description:
- * Build a Scsi_Cmnd structure to perform negotiation with or else send
- * a pre-built command specifically for this purpose.
- *-F*************************************************************************/
-static void
-aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
- int tindex)
-{
-
- if ( !(p->dtr_pending & (1<<tindex)) &&
- ( (p->needppr & (1<<tindex)) ||
- (p->needwdtr & (1<<tindex)) ||
- (p->needsdtr & (1<<tindex)) ) )
- {
- if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
- (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
- {
- return;
- }
- /*
- * Before sending this thing out, we also make the cmd->next pointer
- * point to the real command so we can stuff any possible SENSE data
- * into the real command instead of this fake command. This has to be
- * done each time the command is built, not just the first time, hence
- * it's outside of the above if()...
- */
- p->dev_dtr_cmnd[tindex]->next = old_cmd;
- /*
- * Clear the buffer so checksums come out right....
- */
- memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
- p->dev_dtr_cmnd[tindex]->request_bufflen);
- /*
- * Remove any commands for this particular device that might be on the
- * waiting_scbs queue or qinfifo so that this command goes out first.
- * This is vital for our implementation of domain validation.
- */
- pause_sequencer(p);
- aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
- SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
- unpause_sequencer(p, FALSE);
- {
- struct aic7xxx_scb *scb, *next;
-
- scb = p->waiting_scbs.head;
- while(scb != NULL)
- {
- if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
- ALL_LUNS, SCB_LIST_NULL) )
- {
- next = scb->q_next;
- scbq_remove(&p->waiting_scbs, scb);
- scbq_insert_tail(&p->delayed_scbs[tindex], scb);
- scb = next;
- }
- else
- {
- scb = scb->q_next;
- }
- }
- }
- aic7xxx_queue(p->dev_dtr_cmnd[tindex],
- aic7xxx_negotiation_complete);
- }
-}
-
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/*+F*************************************************************************
* Function:
*/
hscb->control = 0;
scb->tag_action = 0;
- cmd->tag = hscb->tag;
+
if (p->discenable & mask)
{
hscb->control |= DISCENB;
}
}
}
- if ( cmd == p->dev_dtr_cmnd[tindex] )
+ if ( !(p->dtr_pending & mask) &&
+ ( (p->needppr & mask) ||
+ (p->needwdtr & mask) ||
+ (p->needsdtr & mask) ) &&
+ (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
{
p->dtr_pending |= mask;
scb->tag_action = 0;
- if (p->dev_flags[tindex] & DEVICE_SCANNED)
+ hscb->control &= DISCENB;
+ hscb->control |= MK_MESSAGE;
+ if(p->needppr & mask)
{
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- if(p->needppr & mask)
- {
- scb->flags |= SCB_MSGOUT_PPR;
- }
- else if(p->needwdtr & mask)
- {
- scb->flags |= SCB_MSGOUT_WDTR;
- }
- else if(p->needsdtr & mask)
- {
- scb->flags |= SCB_MSGOUT_SDTR;
- }
+ scb->flags |= SCB_MSGOUT_PPR;
}
- }
- if ( !(p->dtr_pending & mask) &&
- ( (p->needppr & mask) ||
- (p->needwdtr & mask) ||
- (p->needsdtr & mask) ) )
- {
- aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
+ else if(p->needwdtr & mask)
+ {
+ scb->flags |= SCB_MSGOUT_WDTR;
+ }
+ else if(p->needsdtr & mask)
+ {
+ scb->flags |= SCB_MSGOUT_SDTR;
+ }
+ scb->flags |= SCB_DTR_SCB;
}
hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
aic7xxx_allocate_scb(p);
DRIVER_UNLOCK
scb = scbq_remove_head(&p->scb_data->free_scbs);
+ if(scb == NULL)
+ printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+ CTL_OF_CMD(cmd));
}
- if (scb == NULL)
+ while (scb == NULL)
{
- printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
- CTL_OF_CMD(cmd));
- cmd->result = (DID_BUS_BUSY << 16);
+ /*
+ * Well, all SCBs are currently active on the bus. So, we spin here
+ * running the interrupt handler until one completes and becomes free.
+ * We can do this safely because we either A) hold the driver lock (in
+ * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
+ * kernels) and so either way, we won't take any other interrupts and
+ * the queue path will block until we release it. Also, we would worry
+ * about running the completion queues, but obviously there are plenty
+ * of commands outstanding to trigger a later interrupt that will do
+ * that for us, so skip it here.
+ */
DRIVER_LOCK
- aic7xxx_queue_cmd_complete(p, cmd);
+ aic7xxx_isr(p->irq, p, NULL);
DRIVER_UNLOCK
- return 0;
+ scb = scbq_remove_head(&p->scb_data->free_scbs);
}
- else
- {
- scb->cmd = cmd;
- aic7xxx_position(cmd) = scb->hscb->tag;
+ scb->cmd = cmd;
+ aic7xxx_position(cmd) = scb->hscb->tag;
- /*
- * Construct the SCB beforehand, so the sequencer is
- * paused a minimal amount of time.
- */
- aic7xxx_buildscb(p, cmd, scb);
+ /*
+ * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+ * is set up properly, and the parity error flag is reset, then send
+ * the SCB to the sequencer and watch the fun begin.
+ */
+ cmd->scsi_done = fn;
+ cmd->result = DID_OK;
+ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ aic7xxx_error(cmd) = DID_OK;
+ aic7xxx_status(cmd) = 0;
+ cmd->host_scribble = NULL;
- /*
- * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
- * is set up properly, and the parity error flag is reset, then send
- * the SCB to the sequencer and watch the fun begin.
- */
- cmd->scsi_done = fn;
- cmd->result = DID_OK;
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- aic7xxx_error(cmd) = DID_OK;
- aic7xxx_status(cmd) = 0;
- cmd->host_scribble = NULL;
+ /*
+ * Construct the SCB beforehand, so the sequencer is
+ * paused a minimal amount of time.
+ */
+ aic7xxx_buildscb(p, cmd, scb);
- scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+ scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
- DRIVER_LOCK
- scbq_insert_tail(&p->waiting_scbs, scb);
- if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
- {
- aic7xxx_run_waiting_queues(p);
- }
- DRIVER_UNLOCK
+ DRIVER_LOCK
+ scbq_insert_tail(&p->waiting_scbs, scb);
+ if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
+ {
+ aic7xxx_run_waiting_queues(p);
}
+ DRIVER_UNLOCK
return (0);
}
aic_inb(p, SCSISIGI),
aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no,
+ CTL_OF_SCB(scb),
+ (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+ aic_inb(p, SSTAT2),
+ aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
+ aic_inb(p, STCNT));
}
channel = cmd->channel;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
unsigned long cpu_flags = 0;
#endif
- Scsi_Cmnd *cmd_next, *cmd_prev;
p = (struct aic7xxx_host *) cmd->host->hostdata;
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
* I added a new config option to the driver: "panic_on_abort" that will
* cause the driver to panic and the machine to stop on the first abort
* or reset call into the driver. At that point, it prints out a lot of
- * usefull information for me which I can then use to try and debug the
+ * useful information for me which I can then use to try and debug the
* problem. Simply enable the boot time prompt in order to activate this
* code.
*/
{
aic7xxx_isr(p->irq, p, (void *)NULL);
pause_sequencer(p);
- aic7xxx_done_cmds_complete(p);
}
+ aic7xxx_done_cmds_complete(p);
- if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
- /* Totally bogus cmd since it points beyond our */
- { /* valid SCB range or doesn't even match it's own*/
- /* timeout serial number. */
+ if (scb == NULL)
+ {
if (aic7xxx_verbose & VERBOSE_ABORT_MID)
printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
"pointer.\n", p->host_no, CTL_OF_CMD(cmd));
/* finish successfully, or to indicate that we */
/* don't have this cmd any more and the mid level */
/* code needs to find it. */
- cmd_next = p->completeq.head;
- cmd_prev = NULL;
- while (cmd_next != NULL)
- {
- if (cmd_next == cmd)
- {
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "Abort called for command "
- "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
- if ( cmd_prev == NULL )
- p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
- else
- cmd_prev->host_scribble = cmd_next->host_scribble;
- cmd_next->scsi_done(cmd_next);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
- * completion */
- }
- cmd_prev = cmd_next;
- cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
- }
if (aic7xxx_verbose & VERBOSE_ABORT_MID)
printk(INFO_LEAD "Abort called for already completed"
" command.\n", p->host_no, CTL_OF_CMD(cmd));
found = 0;
p->flags |= AHC_IN_ABORT;
if (aic7xxx_verbose & VERBOSE_ABORT)
- printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
- p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ {
+ printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
+ "0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, LASTPHASE));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
+ aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
+ aic_inb(p, SCSISIGI));
+ printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
+ aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+ }
/*
* First, let's check to see if the currently running command is our target
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB is currently active. "
"Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+ "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+ aic_inb(p, SCSISIGI),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb),
+ (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+ aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+ aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
unpause_sequencer(p, FALSE);
p->flags &= ~AHC_IN_ABORT;
scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */
if ((found == 0) && (scb->flags & SCB_WAITINGQ))
{
int tindex = TARGET_INDEX(cmd);
- unsigned short mask;
- mask = (1 << tindex);
-
- if (p->dtr_pending & mask)
- {
- if (p->dev_dtr_cmnd[tindex]->next != cmd)
- found = 1;
- else
- found = 0;
- }
- else
- {
- found = 1;
- }
- if (found == 0)
- {
- /*
- * OK..this means the command we are currently getting an abort
- * for has an outstanding negotiation command in front of it.
- * We don't really have a way to tie back into the negotiation
- * commands, so we just send this back as pending, then it
- * will get reset in 2 seconds.
- */
- unpause_sequencer(p, TRUE);
- scb->flags |= SCB_ABORT;
- DRIVER_UNLOCK
- return(SCSI_ABORT_PENDING);
- }
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB found on waiting list and "
"aborted.\n", p->host_no, CTL_OF_SCB(scb));
#define DEVICE_RESET 0x01
#define BUS_RESET 0x02
#define HOST_RESET 0x04
-#define FAIL 0x08
-#define RESET_DELAY 0x10
+#define RESET_DELAY 0x08
int action;
- Scsi_Cmnd *cmd_prev, *cmd_next;
if ( cmd == NULL )
* I added a new config option to the driver: "panic_on_abort" that will
* cause the driver to panic and the machine to stop on the first abort
* or reset call into the driver. At that point, it prints out a lot of
- * usefull information for me which I can then use to try and debug the
+ * useful information for me which I can then use to try and debug the
* problem. Simply enable the boot time prompt in order to activate this
* code.
*/
DRIVER_LOCK
pause_sequencer(p);
- while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
- {
- aic7xxx_isr(p->irq, p, (void *)NULL );
- pause_sequencer(p);
- aic7xxx_done_cmds_complete(p);
- }
- if (scb == NULL)
+ if(flags & SCSI_RESET_SYNCHRONOUS)
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
- "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
- if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
- {
- action = HOST_RESET;
- }
- else
- {
- action = BUS_RESET;
- }
+ printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
+ "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
+ cmd->result);
+ scb = NULL;
+ action = HOST_RESET;
}
- else if (scb->cmd != cmd)
+ else if ((scb == NULL) || (scb->cmd != cmd))
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called with recycled SCB "
- "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
- cmd_prev = NULL;
- cmd_next = p->completeq.head;
- while ( cmd_next != NULL )
- {
- if (cmd_next == cmd)
- {
- if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
- printk(INFO_LEAD "Reset, found cmd on completeq"
- ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_NOT_RUNNING);
- }
- cmd_prev = cmd_next;
- cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
- }
- if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
- {
- if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
- printk(INFO_LEAD "Reset, cmd not found,"
- " failing.\n", p->host_no, CTL_OF_CMD(cmd));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_NOT_RUNNING);
- }
- else
- {
- if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called, no scb, "
- "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
- scb = NULL;
- action = HOST_RESET;
- }
+ printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+ "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
+ aic7xxx_done_cmds_complete(p);
+ aic7xxx_run_waiting_queues(p);
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_NOT_RUNNING);
}
else
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
printk(INFO_LEAD "Reset called, scb %d, flags "
"0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
- if ( aic7xxx_scb_on_qoutfifo(p, scb) )
- {
- if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
- printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
- CTL_OF_SCB(scb));
- if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
- printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
- CTL_OF_SCB(scb));
- aic7xxx_handle_command_completion_intr(p);
- aic7xxx_done_cmds_complete(p);
- aic7xxx_run_waiting_queues(p);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_SUCCESS);
- }
if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
{
action = HOST_RESET;
action = DEVICE_RESET;
}
}
+
+ while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+ {
+ aic7xxx_isr(p->irq, p, (void *)NULL );
+ pause_sequencer(p);
+ }
+ aic7xxx_done_cmds_complete(p);
+
+ if(scb && (scb->cmd == NULL))
+ {
+ /*
+ * We just completed the command when we ran the isr stuff, so we no
+ * longer have it.
+ */
+ aic7xxx_run_waiting_queues(p);
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_SUCCESS);
+ }
+
if ( (action & DEVICE_RESET) &&
(p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
{
switch (action)
{
case RESET_DELAY:
+ aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
DRIVER_UNLOCK
- return(SCSI_RESET_PENDING);
- break;
- case FAIL:
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_ERROR);
+ if(scb == NULL)
+ return(SCSI_RESET_PUNT);
+ else
+ return(SCSI_RESET_PENDING);
break;
case DEVICE_RESET:
p->flags |= AHC_IN_RESET;
case HOST_RESET:
default:
p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
- p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+ p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
p->dev_timer_active |= (0x01 << p->scsi_id);
if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
p->msg_index = 0;
p->msg_len = 0;
}
- aic7xxx_run_done_queue(p, TRUE);
- /*
- * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
- * in need of being re-started, so send it on through to aic7xxx_queue
- * and let it set until the delay is over. This keeps it from dying
- * entirely and avoids getting a bogus dead command back through the
- * mid-level code due to too many retries.
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
- if ( flags & SCSI_RESET_SYNCHRONOUS )
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ if(flags & SCSI_RESET_SYNCHRONOUS)
{
- cmd->result = DID_BUS_BUSY << 16;
+ cmd->result = DID_RESET << 16;
cmd->done(cmd);
}
#endif
+ aic7xxx_run_done_queue(p, TRUE);
p->flags &= ~AHC_IN_RESET;
/*
* We can't rely on run_waiting_queues to unpause the sequencer for
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
DRIVER_UNLOCK
- return(result);
+ if(scb == NULL)
+ return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
+ else
+ return(result);
break;
}
}
information in the process. Second, if you specify the option
"aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
information as it runs that you won't be able to see anything.
- However, this can actually be very usefull if your machine simply
+ However, this can actually be very useful if your machine simply
locks up when trying to boot, since it will pin-point what was last
happening (in regards to the aic7xxx driver) immediately prior to
- the lockup. This is really only usefull if your machine simply can
+ the lockup. This is really only useful if your machine simply can
not boot up successfully. If you can get your machine to run, then
this will produce far too much information.
* it that it can fill the
* message buffer.
*/
- mask TRACEPOINT 0xb0|SEQINT
+ mask SEQ_SG_FIXUP 0xb0|SEQINT /* need help with fixing up
+ * the sg array pointer after
+ * a phasemis with no valid
+ * sg elements in the shadow
+ * pipeline.
+ */
mask TRACEPOINT2 0xc0|SEQINT
mask MSGIN_PHASEMIS 0xd0|SEQINT /*
* Target changed phase on us
/* clear target specific flags */
clr SEQ_FLAGS ret;
+
+data_phase_reinit:
/*
* If we re-enter the data phase after going through another phase, the
* STCNT may have been cleared, so restore it from the residual field.
+ * On Ultra2, we have to put it into the HCNT field because we have to
+ * drop the data down into the shadow layer via the preload ability.
*/
-data_phase_reinit:
- if ((p->features & AHC_ULTRA2) != 0) {
+ if ((p->features & AHC_ULTRA2) != 0) {
bmov HADDR, SHADDR, 4;
bmov HCNT, SCB_RESID_DCNT, 3;
}
mvi SCB_RESID_DCNT call bcopy_3;
}
jmp data_phase_loop;
-
p_data:
- if ((p->features & AHC_ULTRA2) != 0) {
+ if ((p->features & AHC_ULTRA2) != 0) {
mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
} else {
mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
}
test LASTPHASE, IOI jnz . + 2;
or DMAPARAMS, DIRECTION;
- call assert; /*
- * Ensure entering a data
- * phase is okay - seen identify, etc.
- */
+ call assert; /*
+ * Ensure entering a data
+ * phase is okay - seen identify, etc.
+ */
if ((p->features & AHC_CMD_CHAN) != 0) {
mvi CCSGADDR, CCSGADDR_MAX;
}
- test SEQ_FLAGS, DPHASE jnz data_phase_reinit;
-
- /* We have seen a data phase */
- or SEQ_FLAGS, DPHASE;
+ test SEQ_FLAGS, DPHASE jnz data_phase_reinit;
+ or SEQ_FLAGS, DPHASE; /* we've seen a data phase */
/*
* Initialize the DMA address and counter from the SCB.
* Also set SG_COUNT and SG_NEXT in memory since we cannot
*/
if ((p->features & AHC_CMD_CHAN) != 0) {
bmov HADDR, SCB_DATAPTR, 7;
- bmov STCNT, HCNT, 3;
bmov SG_COUNT, SCB_SGCOUNT, 5;
+ if ((p->features & AHC_ULTRA2) == 0) {
+ bmov STCNT, HCNT, 3;
+ }
} else {
mvi DINDEX, HADDR;
mvi SCB_DATAPTR call bcopy_7;
mvi DINDEX, SG_COUNT;
mvi SCB_SGCOUNT call bcopy_5;
}
-
data_phase_loop:
-/* Guard against overruns */
+ /* Guard against overruns */
test SG_COUNT, 0xff jnz data_phase_inbounds;
/*
* Turn on 'Bit Bucket' mode, set the transfer count to
*/
or SXFRCTL1,BITBUCKET;
and DMAPARAMS, ~(HDMAEN|SDMAEN);
- if ((p->features & AHC_CMD_CHAN) != 0) {
- if ((p->features & AHC_ULTRA2) != 0) {
- bmov HCNT, ALLONES, 3;
- }
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov HCNT, ALLONES, 3;
+ }
+ if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
bmov STCNT, ALLONES, 3;
- } else {
+ }
+ if ((p->features & AHC_CMD_CHAN) == 0) {
mvi STCNT[0], 0xFF;
mvi STCNT[1], 0xFF;
mvi STCNT[2], 0xFF;
}
+
data_phase_inbounds:
/* If we are the last SG block, tell the hardware. */
- cmp SG_COUNT,0x01 jne data_phase_wideodd;
- if ((p->features & AHC_ULTRA2) == 0) {
- and DMAPARAMS, ~WIDEODD;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ shl A, 2, SG_COUNT;
+ cmp SG_COUNT,0x01 jne data_phase_wideodd;
+ or A, LAST_SEG;
} else {
- mvi SG_CACHEPTR, LAST_SEG;
+ cmp SG_COUNT,0x01 jne data_phase_wideodd;
+ and DMAPARAMS, ~WIDEODD;
}
data_phase_wideodd:
- if ((p->features & AHC_ULTRA2) != 0) {
- mov SINDEX, ALLONES;
- mov DFCNTRL, DMAPARAMS;
- test SSTAT0, SDONE jnz .;
-data_phase_dma_loop:
- test SSTAT0, SDONE jnz data_phase_dma_done;
- test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
-data_phase_dma_phasemis:
- test SSTAT0,SDONE jnz data_phase_dma_done;
- clr SINDEX; /* Remember the phasemiss */
+ if ((p->features & AHC_ULTRA2) != 0) {
+ mov SG_CACHEPTR, A;
+ mov DFCNTRL, DMAPARAMS; /* start the operation */
+ test SXFRCTL1, BITBUCKET jnz data_phase_overrun;
+u2_preload_wait:
+ test SSTAT1, PHASEMIS jnz u2_phasemis;
+ test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait;
} else {
mov DMAPARAMS call dma;
- }
-
data_phase_dma_done:
/* Go tell the host about any overruns */
- test SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+ test SXFRCTL1,BITBUCKET jnz data_phase_overrun;
/* Exit if we had an underrun. dma clears SINDEX in this case. */
- test SINDEX,0xff jz data_phase_finish;
-
+ test SINDEX,0xff jz data_phase_finish;
+ }
/*
- * Advance the scatter-gather pointers if needed
+ * Advance the scatter-gather pointers
*/
sg_advance:
- dec SG_COUNT; /* one less segment to go */
+ if ((p->features & AHC_ULTRA2) != 0) {
+ cmp SG_COUNT, 0x01 je u2_data_phase_finish;
+ } else {
+ dec SG_COUNT;
+ test SG_COUNT, 0xff jz data_phase_finish;
+ }
- test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes little-endian host data storage.
- */
-sg_load:
if ((p->features & AHC_CMD_CHAN) != 0) {
+
/*
* Do we have any prefetch left???
*/
- cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+ cmp CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
/*
* Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
and CCSGCTL, ~CCSGEN;
test CCSGCTL, CCSGEN jnz .;
mvi CCSGCTL, CCSGRESET;
-prefetched_segs_avail:
+prefetch_avail:
bmov HADDR, CCSGRAM, 8;
if ((p->features & AHC_ULTRA2) == 0) {
bmov STCNT, HCNT, 3;
+ } else {
+ dec SG_COUNT;
}
} else {
mvi DINDEX, HADDR;
call dma_finish;
- /*
- * Copy data from FIFO into SCB data pointer and data count.
- * This assumes that the SG segments are of the form:
- * struct ahc_dma_seg {
- * u_int32_t addr; four bytes, little-endian order
- * u_int32_t len; four bytes, little endian order
- * };
- */
- mvi HADDR call dfdat_in_7;
+/*
+ * Copy data from FIFO into SCB data pointer and data count.
+ * This assumes that the SG segments are of the form:
+ * struct ahc_dma_seg {
+ * u_int32_t addr; four bytes, little-endian order
+ * u_int32_t len; four bytes, little endian order
+ * };
+ */
+ mvi DINDEX, HADDR;
+ call dfdat_in_7;
call set_stcnt_from_hcnt;
}
-
/* Advance the SG pointer */
- clr A; /* add sizeof(struct scatter) */
+ clr A; /* add sizeof(struct scatter) */
add SG_NEXT[0],SG_SIZEOF;
adc SG_NEXT[1],A;
- test SSTAT1, REQINIT jz .;
- test SSTAT1,PHASEMIS jz data_phase_loop;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ jmp data_phase_loop;
+ } else {
+ test SSTAT1, REQINIT jz .;
+ test SSTAT1,PHASEMIS jz data_phase_loop;
+ }
-/* This drops the last SG segment down to the shadow layer for us */
+
+/*
+ * We've loaded all of our segments into the preload layer. Now, we simply
+ * have to wait for it to finish or for us to get a phasemis. And, since
+ * we'll get a phasemis if we do finish, all we really need to do is wait
+ * for a phasemis then check if we did actually complete all the segments.
+ */
if ((p->features & AHC_ULTRA2) != 0) {
- mov DFCNTRL, DMAPARAMS;
- test SSTAT0, SDONE jnz .;
+u2_data_phase_finish:
+ test SSTAT1, PHASEMIS jnz u2_phasemis;
+ test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish;
+ clr SG_COUNT;
+ test SSTAT1, REQINIT jz .;
+ test SSTAT1, PHASEMIS jz data_phase_loop;
+u2_phasemis:
+ call ultra2_dmafinish;
+ test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish;
+ test SSTAT2, SHVALID jnz u2_fixup_residual;
+ mvi INTSTAT, SEQ_SG_FIXUP;
+ jmp data_phase_finish;
+u2_fixup_residual:
+ shr ARG_1, 2, SG_CACHEPTR;
+u2_phasemis_loop:
+ and A, 0x3f, SG_COUNT;
+ cmp ARG_1, A je data_phase_finish;
+/*
+ * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT
+ */
+ clr A;
+ add SG_NEXT[0], -SG_SIZEOF;
+ adc SG_NEXT[1], 0xff;
+ inc SG_COUNT;
+ jmp u2_phasemis_loop;
}
data_phase_finish:
* We use STCNT instead of HCNT, since it's a reflection of how many bytes
* were transferred on the SCSI (as opposed to the host) bus.
*/
- if ((p->features & AHC_ULTRA2) != 0) {
- call ultra2_dmafinish;
- }
- if ((p->features & AHC_ULTRA2) == 0) {
- if ((p->features & AHC_CMD_CHAN) != 0) {
- bmov SCB_RESID_DCNT, STCNT, 3;
- mov SCB_RESID_SGCNT, SG_COUNT;
- } else {
- mov SCB_RESID_DCNT[0],STCNT[0];
- mov SCB_RESID_DCNT[1],STCNT[1];
- mov SCB_RESID_DCNT[2],STCNT[2];
- mov SCB_RESID_SGCNT, SG_COUNT;
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov SCB_RESID_DCNT, STCNT, 3;
+ mov SCB_RESID_SGCNT, SG_COUNT;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
}
+ } else {
+ mov SCB_RESID_DCNT[0],STCNT[0];
+ mov SCB_RESID_DCNT[1],STCNT[1];
+ mov SCB_RESID_DCNT[2],STCNT[2];
+ mov SCB_RESID_SGCNT, SG_COUNT;
}
jmp ITloop;
data_phase_overrun:
- if ((p->features & AHC_ULTRA2) != 0) {
- call ultra2_dmafinish;
- }
/*
* Turn off BITBUCKET mode and notify the host
*/
+ if ((p->features & AHC_ULTRA2) != 0) {
+/*
+ * Wait for the target to quit transferring data on the SCSI bus
+ */
+ test SSTAT1, PHASEMIS jz .;
+ call ultra2_dmafinish;
+ }
and SXFRCTL1, ~BITBUCKET;
mvi INTSTAT,DATA_OVERRUN;
jmp ITloop;
-ultra2_dmafinish:
+
+
+
+/*
+ * Actually turn off the DMA hardware, save our current position into the
+ * proper residual variables, wait for the next REQ signal, then jump to
+ * the ITloop. Jumping to the ITloop ensures that if we happen to get
+ * brought into the data phase again (or are still in it after our last
+ * segment) that we will properly signal an overrun to the kernel.
+ */
if ((p->features & AHC_ULTRA2) != 0) {
+ultra2_dmafinish:
test DFCNTRL, DIRECTION jnz ultra2_dmahalt;
and DFCNTRL, ~SCSIEN;
test DFCNTRL, SCSIEN jnz .;
+ if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+ or DFCNTRL, FIFOFLUSH;
+ }
ultra2_dmafifoflush:
- or DFCNTRL, FIFOFLUSH;
- test DFSTATUS, FIFOEMP jz . - 1;
- /*
- * hardware bug alert! This needless set of jumps is to
- * protect against a FIFOEMP status bit glitch in the
- * silicon.
- */
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
- test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+ /*
+ * hardware bug alert! This needless set of jumps
+ * works around a glitch in the silicon. When the
+ * PCI DMA fifo goes empty, but there is still SCSI
+ * data to be flushed into the PCI DMA fifo (and from
+ * there on into main memory), the FIFOEMP bit will
+ * come on between the time when the PCI DMA buffer
+ * went empty and the next bit of data is copied from
+ * the SCSI fifo into the PCI fifo. It should only
+ * come on when both FIFOs (meaning the entire FIFO
+ * chain) are emtpy. Since it can take up to 4 cycles
+ * for new data to be copied from the SCSI fifo into
+ * the PCI fifo, testing for FIFOEMP status for 4
+ * extra times gives the needed time for any
+ * remaining SCSI fifo data to be put in the PCI fifo
+ * before we declare it *truly* empty.
+ */
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ }
test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
test DFSTATUS, MREQPEND jnz .;
ultra2_dmahalt:
- test SCSIOFFSET, 0x7f jnz ultra2_shutdown;
-ultra2_await_nreq:
- test SCSISIGI, REQI jz ultra2_shutdown;
- test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq;
-ultra2_shutdown:
and DFCNTRL, ~(HDMAEN|SCSIEN);
test DFCNTRL, (HDMAEN|SCSIEN) jnz .;
- bmov SCB_RESID_DCNT, STCNT, 3;
- mov SCB_RESID_SGCNT, SG_COUNT;
- or SXFRCTL0, CLRSTCNT|CLRCHN;
ret;
}
inb_last:
mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
+
mesgin_phasemis:
/*
* We expected to receive another byte, but the target changed phase
* to drain the data fifo until there is space for the input
* latch to drain and HDMAEN de-asserts.
*/
- mov NONE, DFDAT;
+ if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+ mov NONE, DFDAT;
+ }
test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
}
return:
cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
jmp dma_scb_finish;
dma_scb_tohost:
- if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+ if ((p->features & AHC_ULTRA2) == 0) {
mvi CCSCBCTL, CCSCBRESET;
bmov CCSCBRAM, SCB_CONTROL, 32;
or CCSCBCTL, CCSCBEN|CCSCBRESET;
test CCSCBCTL, CCSCBDONE jz .;
- } else {
- mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
- cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+ }
+ if ((p->features & AHC_ULTRA2) != 0) {
+ if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
+ mvi CCSCBCTL, CCARREN|CCSCBRESET;
+ cmp CCSCBCTL, ARRDONE|CCARREN jne .;
+ mvi CCHCNT, 32;
+ mvi CCSCBCTL, CCSCBEN|CCSCBRESET;
+ cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+ } else {
+ mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+ cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+ }
}
dma_scb_finish:
clr CCSCBCTL;
test CCSCBCTL, CCARREN|CCSCBEN jnz .;
ret;
- } else {
+ }
+ if ((p->features & AHC_CMD_CHAN) == 0) {
mvi DINDEX, HADDR;
mvi HSCB_ADDR call set_32byte_addr;
mvi HCNT[0], 32;
mov DFDAT,SINDIR;
cmp SINDEX, A jne copy_scb_tofifo_loop;
or DFCNTRL, HDMAEN|FIFOFLUSH;
+ jmp dma_finish;
dma_scb_fromhost:
- call dma_finish;
- /* If we were putting the SCB, we are done */
- test DMAPARAMS, DIRECTION jz return;
- mvi SCB_CONTROL call dfdat_in_7;
- call dfdat_in_7_continued;
- call dfdat_in_7_continued;
- jmp dfdat_in_7_continued;
+ mvi DINDEX, SCB_CONTROL;
+ if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+ /*
+ * Set the A to -24. It it hits 0, then we let
+ * our code fall through to dfdat_in_8 to complete
+ * the last of the copy.
+ *
+ * Also, things happen 8 bytes at a time in this
+ * case, so we may need to drain the fifo at most
+ * 3 times to keep things flowing
+ */
+ mvi A, -24;
+dma_scb_hang_fifo:
+ /* Wait for the first bit of data to hit the fifo */
+ test DFSTATUS, FIFOEMP jnz .;
+dma_scb_hang_wait:
+ /* OK, now they've started to transfer into the fifo,
+ * so wait for them to stop trying to transfer any
+ * more data.
+ */
+ test DFSTATUS, MREQPEND jnz .;
+ /*
+ * OK, they started, then they stopped, now see if they
+ * managed to complete the job before stopping. Try
+ * it multiple times to give the chip a few cycles to
+ * set the flag if it did complete.
+ */
+ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+ /*
+ * Too bad, the chip didn't complete the DMA, but there
+ * aren't any more memory requests pending, so that
+ * means it stopped part way through and hung. That's
+ * our bug, so now we drain what data there is in the
+ * fifo in order to get things going again.
+ */
+dma_scb_hang_empty_fifo:
+ call dfdat_in_8;
+ add A, 8;
+ add SINDEX, A, HCNT;
+ /*
+ * If there are another 8 bytes of data waiting in the
+ * fifo, then the carry bit will be set as a result
+ * of the above add command (unless A is non-negative,
+ * in which case the carry bit won't be set).
+ */
+ jc dma_scb_hang_empty_fifo;
+ /*
+ * We've emptied the fifo now, but we wouldn't have got
+ * here if the memory transfer hadn't stopped part way
+ * through, so go back up to the beginning of the
+ * loop and start over. When it succeeds in getting
+ * all the data down, HDONE will be set and we'll
+ * jump to the code just below here.
+ */
+ jmp dma_scb_hang_fifo;
+dma_scb_hang_dma_done:
+ and DFCNTRL, ~HDMAEN;
+ test DFCNTRL, HDMAEN jnz .;
+ call dfdat_in_8;
+ add A, 8;
+ cmp A, 8 jne . - 2;
+ ret;
+ } else {
+ call dma_finish;
+ call dfdat_in_8;
+ call dfdat_in_8;
+ call dfdat_in_8;
+ }
+dfdat_in_8:
+ mov DINDIR,DFDAT;
dfdat_in_7:
- mov DINDEX,SINDEX;
-dfdat_in_7_continued:
mov DINDIR,DFDAT;
mov DINDIR,DFDAT;
mov DINDIR,DFDAT;
size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Compile Options:\n");
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n");
#else
size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n");
#define BRDRW 0x04
#define BRDRW_ULTRA2 0x02
#define BRDCTL1 0x02
-#define BRDCTL0 0x01
#define BRDSTB_ULTRA2 0x01
+#define BRDCTL0 0x01
#define SEECTL 0x1e
#define EXTARBACK 0x80
#define DATA_OVERRUN 0xe1
#define MSGIN_PHASEMIS 0xd1
#define TRACEPOINT2 0xc1
-#define TRACEPOINT 0xb1
+#define SEQ_SG_FIXUP 0xb1
#define AWAITING_MSG 0xa1
#define RESIDUAL 0x81
#define BAD_STATUS 0x71
#define TARGCRCENDEN 0x08
#define TARGCRCCNTEN 0x04
-#define QOUTCNT 0x9e
-
#define SCSIPHASE 0x9e
#define SP_STATUS 0x20
#define SP_COMMAND 0x10
#define SP_DATA_IN 0x02
#define SP_DATA_OUT 0x01
+#define QOUTCNT 0x9e
+
#define SFUNCT 0x9f
#define ALT_MODE 0x80
#define RD_DFTHRSH_63 0x03
#define RD_DFTHRSH_50 0x02
#define RD_DFTHRSH_25 0x01
-#define RD_DFTHRSH_MIN 0x00
#define WR_DFTHRSH_MIN 0x00
+#define RD_DFTHRSH_MIN 0x00
#define SG_CACHEPTR 0xfc
#define SG_USER_DATA 0xfc
#define LAST_SEG_DONE 0x01
-#define CMD_GROUP_CODE_SHIFT 0x05
-#define BUS_8_BIT 0x00
-#define QOUTFIFO_OFFSET 0x01
-#define CCSGRAM_MAXSEGS 0x10
#define CMD_GROUP2_BYTE_DELTA 0xfa
#define MAX_OFFSET_8BIT 0x0f
#define BUS_16_BIT 0x01
#define QINFIFO_OFFSET 0x02
#define CMD_GROUP5_BYTE_DELTA 0x0b
+#define CMD_GROUP_CODE_SHIFT 0x05
#define MAX_OFFSET_ULTRA2 0x7f
#define MAX_OFFSET_16BIT 0x08
+#define BUS_8_BIT 0x00
+#define QOUTFIFO_OFFSET 0x01
#define UNTAGGEDSCB_OFFSET 0x00
+#define CCSGRAM_MAXSEGS 0x10
#define SCB_LIST_NULL 0xff
#define SG_SIZEOF 0x08
#define CMD_GROUP4_BYTE_DELTA 0x04
0x00, 0x4d, 0x10, 0x70,
0x01, 0x4e, 0x9c, 0x18,
0xbf, 0x60, 0xc0, 0x08,
- 0x00, 0x6a, 0x3e, 0x5c,
+ 0x00, 0x6a, 0x86, 0x5c,
0xff, 0x4e, 0xc8, 0x18,
- 0x02, 0x6a, 0x54, 0x5b,
+ 0x02, 0x6a, 0x70, 0x5b,
0xff, 0x52, 0x20, 0x09,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x52, 0xca, 0x5b,
+ 0x00, 0x52, 0xe6, 0x5b,
0x03, 0xb0, 0x52, 0x31,
0xff, 0xb0, 0x52, 0x09,
0xff, 0xb1, 0x54, 0x09,
0x08, 0x6a, 0x66, 0x58,
0x80, 0x6a, 0x68, 0x00,
0x80, 0x36, 0x6c, 0x00,
- 0x00, 0x65, 0x9e, 0x5b,
+ 0x00, 0x65, 0xba, 0x5b,
0xff, 0x3d, 0xc8, 0x08,
0xbf, 0x64, 0xe2, 0x78,
- 0x80, 0x64, 0xac, 0x71,
- 0xa0, 0x64, 0xdc, 0x71,
- 0xc0, 0x64, 0xd4, 0x71,
- 0xe0, 0x64, 0x1c, 0x72,
+ 0x80, 0x64, 0xc8, 0x71,
+ 0xa0, 0x64, 0xf8, 0x71,
+ 0xc0, 0x64, 0xf0, 0x71,
+ 0xe0, 0x64, 0x38, 0x72,
0x01, 0x6a, 0x22, 0x01,
0x00, 0x65, 0xaa, 0x40,
0xf7, 0x11, 0x22, 0x08,
0x03, 0xa9, 0x18, 0x31,
0x03, 0xa9, 0x10, 0x30,
0x08, 0x6a, 0xcc, 0x00,
- 0xa9, 0x6a, 0xb4, 0x5b,
+ 0xa9, 0x6a, 0xd0, 0x5b,
0x00, 0x65, 0x02, 0x41,
0xa8, 0x6a, 0x6a, 0x00,
0x79, 0x6a, 0x6a, 0x00,
0x40, 0x3d, 0xea, 0x68,
0x04, 0x35, 0x6a, 0x00,
- 0x00, 0x65, 0x0e, 0x5b,
+ 0x00, 0x65, 0x2a, 0x5b,
0x80, 0x6a, 0xd4, 0x01,
0x10, 0x36, 0xd6, 0x68,
0x10, 0x36, 0x6c, 0x00,
0x07, 0xac, 0x10, 0x31,
- 0x03, 0x8c, 0x10, 0x30,
0x05, 0xa3, 0x70, 0x30,
+ 0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xac, 0x6a, 0xac, 0x5b,
- 0x00, 0x65, 0xa6, 0x5b,
+ 0xac, 0x6a, 0xc8, 0x5b,
+ 0x00, 0x65, 0xc2, 0x5b,
0x38, 0x6a, 0xcc, 0x00,
- 0xa3, 0x6a, 0xb0, 0x5b,
+ 0xa3, 0x6a, 0xcc, 0x5b,
0xff, 0x38, 0x12, 0x69,
0x80, 0x02, 0x04, 0x00,
0xe7, 0x35, 0x6a, 0x08,
0xff, 0x6a, 0x10, 0x00,
0xff, 0x6a, 0x12, 0x00,
0xff, 0x6a, 0x14, 0x00,
- 0x01, 0x38, 0x18, 0x61,
+ 0x22, 0x38, 0xc8, 0x28,
+ 0x01, 0x38, 0x1c, 0x61,
+ 0x02, 0x64, 0xc8, 0x00,
+ 0x01, 0x38, 0x1c, 0x61,
0xbf, 0x35, 0x6a, 0x08,
- 0x02, 0x6a, 0xf8, 0x01,
- 0xff, 0x69, 0xca, 0x08,
+ 0xff, 0x64, 0xf8, 0x09,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0x1c, 0x69,
- 0x04, 0x0b, 0x28, 0x69,
- 0x10, 0x0c, 0x1e, 0x79,
- 0x04, 0x0b, 0x28, 0x69,
- 0xff, 0x6a, 0xca, 0x08,
- 0x00, 0x35, 0xee, 0x5a,
- 0x80, 0x02, 0x7c, 0x69,
- 0xff, 0x65, 0x6c, 0x79,
+ 0x80, 0x02, 0xa4, 0x69,
+ 0x10, 0x0c, 0x7a, 0x69,
+ 0x80, 0x94, 0x22, 0x79,
+ 0x00, 0x35, 0x0a, 0x5b,
+ 0x80, 0x02, 0xa4, 0x69,
+ 0xff, 0x65, 0x94, 0x79,
+ 0x01, 0x38, 0x70, 0x71,
0xff, 0x38, 0x70, 0x18,
- 0xff, 0x38, 0x6c, 0x79,
- 0x80, 0xea, 0x48, 0x61,
+ 0xff, 0x38, 0x94, 0x79,
+ 0x80, 0xea, 0x4a, 0x61,
0xef, 0x38, 0xc8, 0x18,
0x80, 0x6a, 0xc8, 0x00,
- 0x00, 0x65, 0x3a, 0x49,
+ 0x00, 0x65, 0x3c, 0x49,
0x33, 0x38, 0xc8, 0x28,
0xff, 0x64, 0xd0, 0x09,
0x04, 0x39, 0xc0, 0x31,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0x40, 0x79,
+ 0x80, 0xeb, 0x42, 0x79,
0xf7, 0xeb, 0xd6, 0x09,
- 0x08, 0xeb, 0x44, 0x69,
+ 0x08, 0xeb, 0x46, 0x69,
0x01, 0x6a, 0xd6, 0x01,
0x08, 0xe9, 0x10, 0x31,
0x03, 0x8c, 0x10, 0x30,
+ 0xff, 0x38, 0x70, 0x18,
0x88, 0x6a, 0xcc, 0x00,
- 0x39, 0x6a, 0xb2, 0x5b,
+ 0x39, 0x6a, 0xce, 0x5b,
0x08, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x30, 0x5c,
- 0x88, 0x6a, 0x20, 0x5c,
- 0x00, 0x65, 0xa6, 0x5b,
+ 0x00, 0x65, 0x78, 0x5c,
+ 0x88, 0x6a, 0xcc, 0x00,
+ 0x00, 0x65, 0x6a, 0x5c,
+ 0x00, 0x65, 0xc2, 0x5b,
0xff, 0x6a, 0xc8, 0x08,
0x08, 0x39, 0x72, 0x18,
0x00, 0x3a, 0x74, 0x20,
- 0x01, 0x0c, 0x64, 0x79,
+ 0x00, 0x65, 0x02, 0x41,
+ 0x01, 0x0c, 0x6c, 0x79,
0x10, 0x0c, 0x02, 0x79,
- 0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0x6a, 0x69,
- 0x00, 0x65, 0x84, 0x59,
+ 0x10, 0x0c, 0x7a, 0x69,
+ 0x01, 0xfc, 0x70, 0x79,
+ 0xff, 0x6a, 0x70, 0x08,
+ 0x01, 0x0c, 0x76, 0x79,
+ 0x10, 0x0c, 0x02, 0x79,
+ 0x00, 0x65, 0xae, 0x59,
+ 0x01, 0xfc, 0x94, 0x69,
+ 0x40, 0x0d, 0x84, 0x69,
+ 0xb1, 0x6a, 0x22, 0x01,
+ 0x00, 0x65, 0x94, 0x41,
+ 0x2e, 0xfc, 0xa2, 0x28,
+ 0x3f, 0x38, 0xc8, 0x08,
+ 0x00, 0x51, 0x94, 0x71,
+ 0xff, 0x6a, 0xc8, 0x08,
+ 0xf8, 0x39, 0x72, 0x18,
+ 0xff, 0x3a, 0x74, 0x20,
+ 0x01, 0x38, 0x70, 0x18,
+ 0x00, 0x65, 0x86, 0x41,
0x03, 0x08, 0x52, 0x31,
0xff, 0x38, 0x50, 0x09,
+ 0x12, 0x01, 0x02, 0x00,
0xff, 0x08, 0x52, 0x09,
0xff, 0x09, 0x54, 0x09,
0xff, 0x0a, 0x56, 0x09,
0xff, 0x38, 0x50, 0x09,
0x00, 0x65, 0xaa, 0x40,
- 0x00, 0x65, 0x84, 0x59,
+ 0x10, 0x0c, 0xa4, 0x79,
+ 0x00, 0x65, 0xae, 0x59,
0x7f, 0x02, 0x04, 0x08,
0xe1, 0x6a, 0x22, 0x01,
0x00, 0x65, 0xaa, 0x40,
- 0x04, 0x93, 0x9a, 0x69,
+ 0x04, 0x93, 0xc2, 0x69,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x88, 0x69,
+ 0x20, 0x93, 0xb2, 0x69,
0x02, 0x93, 0x26, 0x01,
- 0x01, 0x94, 0x8a, 0x79,
- 0x01, 0x94, 0x8a, 0x79,
- 0x01, 0x94, 0x8a, 0x79,
- 0x01, 0x94, 0x8a, 0x79,
- 0x01, 0x94, 0x8a, 0x79,
- 0x01, 0x94, 0x8a, 0x79,
- 0x10, 0x94, 0x98, 0x69,
- 0x7f, 0x05, 0xa0, 0x69,
- 0x02, 0x03, 0xa0, 0x79,
- 0x11, 0x0c, 0x9c, 0x79,
+ 0x01, 0x94, 0xb6, 0x79,
+ 0x01, 0x94, 0xb6, 0x79,
+ 0x01, 0x94, 0xb6, 0x79,
+ 0x01, 0x94, 0xb6, 0x79,
+ 0x01, 0x94, 0xb6, 0x79,
+ 0x10, 0x94, 0xc0, 0x69,
0xd7, 0x93, 0x26, 0x09,
- 0x28, 0x93, 0xa2, 0x69,
- 0x03, 0x08, 0x52, 0x31,
- 0xff, 0x38, 0x50, 0x09,
- 0x12, 0x01, 0x02, 0x00,
+ 0x28, 0x93, 0xc4, 0x69,
0xff, 0x6a, 0xd4, 0x0c,
- 0x00, 0x65, 0x0e, 0x5b,
+ 0x00, 0x65, 0x2a, 0x5b,
0x05, 0xb4, 0x10, 0x31,
0x02, 0x6a, 0x1a, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xb4, 0x6a, 0xb0, 0x5b,
+ 0xb4, 0x6a, 0xcc, 0x5b,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
- 0x00, 0x65, 0xa6, 0x5b,
- 0x3d, 0x6a, 0xee, 0x5a,
+ 0x00, 0x65, 0xc2, 0x5b,
+ 0x3d, 0x6a, 0x0a, 0x5b,
0xac, 0x6a, 0x26, 0x01,
- 0x04, 0x0b, 0xc2, 0x69,
- 0x04, 0x0b, 0xc8, 0x69,
- 0x10, 0x0c, 0xc4, 0x79,
- 0x02, 0x03, 0xcc, 0x79,
- 0x11, 0x0c, 0xc8, 0x79,
+ 0x04, 0x0b, 0xde, 0x69,
+ 0x04, 0x0b, 0xe4, 0x69,
+ 0x10, 0x0c, 0xe0, 0x79,
+ 0x02, 0x03, 0xe8, 0x79,
+ 0x11, 0x0c, 0xe4, 0x79,
0xd7, 0x93, 0x26, 0x09,
- 0x28, 0x93, 0xce, 0x69,
+ 0x28, 0x93, 0xea, 0x69,
0x12, 0x01, 0x02, 0x00,
0x00, 0x65, 0xaa, 0x40,
- 0x00, 0x65, 0x0e, 0x5b,
+ 0x00, 0x65, 0x2a, 0x5b,
0xff, 0x06, 0x44, 0x09,
0x00, 0x65, 0xaa, 0x40,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x34, 0xca, 0x08,
- 0x80, 0x65, 0x00, 0x62,
+ 0x80, 0x65, 0x1c, 0x62,
0x0f, 0xa1, 0xca, 0x08,
0x07, 0xa1, 0xca, 0x08,
0x40, 0xa0, 0xc8, 0x08,
0x00, 0x65, 0xca, 0x00,
0x80, 0x65, 0xca, 0x00,
- 0x80, 0xa0, 0xf0, 0x79,
+ 0x80, 0xa0, 0x0c, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x02, 0x42,
- 0x20, 0xa0, 0x08, 0x7a,
+ 0x00, 0x65, 0x1e, 0x42,
+ 0x20, 0xa0, 0x24, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x9e, 0x5b,
- 0xa0, 0x3d, 0x10, 0x62,
+ 0x00, 0x65, 0xba, 0x5b,
+ 0xa0, 0x3d, 0x2c, 0x62,
0x23, 0xa0, 0x0c, 0x08,
- 0x00, 0x65, 0x9e, 0x5b,
- 0xa0, 0x3d, 0x10, 0x62,
- 0x00, 0xb9, 0x08, 0x42,
- 0xff, 0x65, 0x08, 0x62,
+ 0x00, 0x65, 0xba, 0x5b,
+ 0xa0, 0x3d, 0x2c, 0x62,
+ 0x00, 0xb9, 0x24, 0x42,
+ 0xff, 0x65, 0x24, 0x62,
0xa1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x10, 0x51, 0x10, 0x72,
+ 0x10, 0x51, 0x2c, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x9e, 0x5b,
- 0xa0, 0x3d, 0xda, 0x71,
+ 0x00, 0x65, 0xba, 0x5b,
+ 0xa0, 0x3d, 0xf6, 0x71,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x34, 0xa6, 0x08,
- 0x80, 0x34, 0x18, 0x62,
+ 0x80, 0x34, 0x34, 0x62,
0x7f, 0xa0, 0x40, 0x09,
0x08, 0x6a, 0x68, 0x00,
0x00, 0x65, 0xaa, 0x40,
- 0x64, 0x6a, 0xe4, 0x5a,
- 0x80, 0x64, 0x8e, 0x6a,
- 0x04, 0x64, 0x70, 0x72,
- 0x02, 0x64, 0x76, 0x72,
- 0x00, 0x6a, 0x38, 0x72,
- 0x03, 0x64, 0x8a, 0x72,
- 0x01, 0x64, 0x6c, 0x72,
- 0x07, 0x64, 0xcc, 0x72,
- 0x08, 0x64, 0x34, 0x72,
- 0x23, 0x64, 0xd0, 0x72,
+ 0x64, 0x6a, 0x00, 0x5b,
+ 0x80, 0x64, 0xaa, 0x6a,
+ 0x04, 0x64, 0x8c, 0x72,
+ 0x02, 0x64, 0x92, 0x72,
+ 0x00, 0x6a, 0x54, 0x72,
+ 0x03, 0x64, 0xa6, 0x72,
+ 0x01, 0x64, 0x88, 0x72,
+ 0x07, 0x64, 0xe8, 0x72,
+ 0x08, 0x64, 0x50, 0x72,
+ 0x23, 0x64, 0xec, 0x72,
0x11, 0x6a, 0x22, 0x01,
- 0x07, 0x6a, 0xd6, 0x5a,
+ 0x07, 0x6a, 0xf2, 0x5a,
0xff, 0x06, 0xd4, 0x08,
0x00, 0x65, 0xaa, 0x40,
- 0xff, 0xa8, 0x3c, 0x6a,
- 0xff, 0xa2, 0x54, 0x7a,
+ 0xff, 0xa8, 0x58, 0x6a,
+ 0xff, 0xa2, 0x70, 0x7a,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0xca, 0x5b,
- 0xff, 0xa2, 0x54, 0x7a,
+ 0x00, 0xb9, 0xe6, 0x5b,
+ 0xff, 0xa2, 0x70, 0x7a,
0x71, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x40, 0x51, 0x54, 0x62,
+ 0x40, 0x51, 0x70, 0x62,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0xca, 0x5b,
+ 0x00, 0xb9, 0xe6, 0x5b,
0xff, 0x3e, 0x74, 0x09,
0xff, 0x90, 0x7c, 0x08,
0x00, 0x65, 0x4e, 0x58,
0x00, 0x65, 0xbc, 0x40,
- 0x20, 0xa0, 0x5c, 0x6a,
+ 0x20, 0xa0, 0x78, 0x6a,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0x74, 0x5b,
- 0xff, 0x6a, 0x8a, 0x5b,
+ 0x00, 0x6a, 0x90, 0x5b,
+ 0xff, 0x6a, 0xa6, 0x5b,
0xff, 0xf8, 0xc8, 0x08,
0xff, 0x4f, 0xc8, 0x08,
- 0x01, 0x6a, 0x74, 0x5b,
- 0x00, 0xb9, 0x8a, 0x5b,
+ 0x01, 0x6a, 0x90, 0x5b,
+ 0x00, 0xb9, 0xa6, 0x5b,
0x01, 0x4f, 0x9e, 0x18,
0x02, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x38, 0x5c,
+ 0x00, 0x65, 0x80, 0x5c,
0x00, 0x65, 0xbc, 0x40,
0x41, 0x6a, 0x22, 0x01,
0x00, 0x65, 0xaa, 0x40,
0x04, 0xa0, 0x40, 0x01,
- 0x00, 0x65, 0x50, 0x5c,
+ 0x00, 0x65, 0x98, 0x5c,
0x00, 0x65, 0xbc, 0x40,
- 0x10, 0x36, 0x34, 0x7a,
+ 0x10, 0x36, 0x50, 0x7a,
0x05, 0x38, 0x46, 0x31,
0x04, 0x14, 0x58, 0x31,
0x03, 0xa9, 0x60, 0x31,
0xa3, 0x6a, 0xcc, 0x00,
- 0x38, 0x6a, 0xb0, 0x5b,
+ 0x38, 0x6a, 0xcc, 0x5b,
0xac, 0x6a, 0xcc, 0x00,
- 0x14, 0x6a, 0xb2, 0x5b,
- 0xa9, 0x6a, 0xb4, 0x5b,
- 0x00, 0x65, 0x34, 0x42,
+ 0x14, 0x6a, 0xce, 0x5b,
+ 0xa9, 0x6a, 0xd0, 0x5b,
+ 0x00, 0x65, 0x50, 0x42,
0xef, 0x36, 0x6c, 0x08,
- 0x00, 0x65, 0x34, 0x42,
+ 0x00, 0x65, 0x50, 0x42,
0x0f, 0x64, 0xc8, 0x08,
0x07, 0x64, 0xc8, 0x08,
0x00, 0x37, 0x6e, 0x00,
0xff, 0x6a, 0xa4, 0x00,
- 0x00, 0x65, 0x44, 0x5b,
- 0xff, 0x51, 0xa0, 0x72,
- 0x20, 0x36, 0xaa, 0x7a,
- 0x00, 0x90, 0x32, 0x5b,
- 0x00, 0x65, 0xac, 0x42,
+ 0x00, 0x65, 0x60, 0x5b,
+ 0xff, 0x51, 0xbc, 0x72,
+ 0x20, 0x36, 0xc6, 0x7a,
+ 0x00, 0x90, 0x4e, 0x5b,
+ 0x00, 0x65, 0xc8, 0x42,
0xff, 0x06, 0xd4, 0x08,
- 0x00, 0x65, 0x9e, 0x5b,
- 0xe0, 0x3d, 0xc6, 0x62,
- 0x20, 0x12, 0xc6, 0x62,
- 0x51, 0x6a, 0xda, 0x5a,
- 0x00, 0x65, 0x2c, 0x5b,
+ 0x00, 0x65, 0xba, 0x5b,
+ 0xe0, 0x3d, 0xe2, 0x62,
+ 0x20, 0x12, 0xe2, 0x62,
+ 0x51, 0x6a, 0xf6, 0x5a,
+ 0x00, 0x65, 0x48, 0x5b,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0xa1, 0xbe, 0x62,
- 0x04, 0xa0, 0xbe, 0x7a,
+ 0x00, 0xa1, 0xda, 0x62,
+ 0x04, 0xa0, 0xda, 0x7a,
0xfb, 0xa0, 0x40, 0x09,
0x80, 0x36, 0x6c, 0x00,
- 0x80, 0xa0, 0x34, 0x7a,
+ 0x80, 0xa0, 0x50, 0x7a,
0x7f, 0xa0, 0x40, 0x09,
- 0xff, 0x6a, 0xd6, 0x5a,
- 0x00, 0x65, 0x34, 0x42,
- 0x04, 0xa0, 0xc4, 0x7a,
- 0x00, 0x65, 0x50, 0x5c,
- 0x00, 0x65, 0xc6, 0x42,
- 0x00, 0x65, 0x38, 0x5c,
+ 0xff, 0x6a, 0xf2, 0x5a,
+ 0x00, 0x65, 0x50, 0x42,
+ 0x04, 0xa0, 0xe0, 0x7a,
+ 0x00, 0x65, 0x98, 0x5c,
+ 0x00, 0x65, 0xe2, 0x42,
+ 0x00, 0x65, 0x80, 0x5c,
0x31, 0x6a, 0x22, 0x01,
- 0x0c, 0x6a, 0xd6, 0x5a,
- 0x00, 0x65, 0x34, 0x42,
+ 0x0c, 0x6a, 0xf2, 0x5a,
+ 0x00, 0x65, 0x50, 0x42,
0x61, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x34, 0x42,
- 0x51, 0x6a, 0xda, 0x5a,
+ 0x00, 0x65, 0x50, 0x42,
+ 0x51, 0x6a, 0xf6, 0x5a,
0x51, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x34, 0x42,
+ 0x00, 0x65, 0x50, 0x42,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x65, 0x68, 0x0c,
0xff, 0x06, 0xd4, 0x08,
- 0x01, 0x0c, 0xdc, 0x7a,
- 0x04, 0x0c, 0xde, 0x6a,
+ 0x01, 0x0c, 0xf8, 0x7a,
+ 0x04, 0x0c, 0xfa, 0x6a,
0xe0, 0x03, 0x7a, 0x08,
- 0xe0, 0x3d, 0xea, 0x62,
+ 0xe0, 0x3d, 0x06, 0x63,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x12, 0xda, 0x0c,
0xff, 0x06, 0xd4, 0x0c,
0xd1, 0x6a, 0x22, 0x01,
0x00, 0x65, 0xaa, 0x40,
0xff, 0x65, 0x26, 0x09,
- 0x01, 0x0b, 0xfe, 0x6a,
- 0x10, 0x0c, 0xf0, 0x7a,
- 0x04, 0x0b, 0xf8, 0x6a,
+ 0x01, 0x0b, 0x1a, 0x6b,
+ 0x10, 0x0c, 0x0c, 0x7b,
+ 0x04, 0x0b, 0x14, 0x6b,
0xff, 0x6a, 0xca, 0x08,
- 0x04, 0x93, 0xfc, 0x6a,
- 0x01, 0x94, 0xfa, 0x7a,
- 0x10, 0x94, 0xfc, 0x6a,
- 0x80, 0x3d, 0x02, 0x73,
- 0x0f, 0x04, 0x06, 0x6b,
- 0x02, 0x03, 0x06, 0x7b,
- 0x11, 0x0c, 0x02, 0x7b,
+ 0x04, 0x93, 0x18, 0x6b,
+ 0x01, 0x94, 0x16, 0x7b,
+ 0x10, 0x94, 0x18, 0x6b,
+ 0x80, 0x3d, 0x1e, 0x73,
+ 0x0f, 0x04, 0x22, 0x6b,
+ 0x02, 0x03, 0x22, 0x7b,
+ 0x11, 0x0c, 0x1e, 0x7b,
0xc7, 0x93, 0x26, 0x09,
0xff, 0x99, 0xd4, 0x08,
- 0x38, 0x93, 0x08, 0x6b,
+ 0x38, 0x93, 0x24, 0x6b,
0xff, 0x6a, 0xd4, 0x0c,
- 0x80, 0x36, 0x0c, 0x6b,
+ 0x80, 0x36, 0x28, 0x6b,
0x21, 0x6a, 0x22, 0x05,
0xff, 0x65, 0x20, 0x09,
- 0xff, 0x51, 0x1a, 0x63,
+ 0xff, 0x51, 0x36, 0x63,
0xff, 0x37, 0xc8, 0x08,
- 0xa1, 0x6a, 0x26, 0x43,
+ 0xa1, 0x6a, 0x42, 0x43,
0xff, 0x51, 0xc8, 0x08,
- 0xb9, 0x6a, 0x26, 0x43,
+ 0xb9, 0x6a, 0x42, 0x43,
0xff, 0x90, 0xa4, 0x08,
- 0xff, 0xba, 0x2a, 0x73,
+ 0xff, 0xba, 0x46, 0x73,
0xff, 0xba, 0x20, 0x09,
0xff, 0x65, 0xca, 0x18,
- 0x00, 0x6c, 0x1e, 0x63,
+ 0x00, 0x6c, 0x3a, 0x63,
0xff, 0x90, 0xca, 0x0c,
0xff, 0x6a, 0xca, 0x04,
- 0x20, 0x36, 0x3e, 0x7b,
- 0x00, 0x90, 0x12, 0x5b,
- 0xff, 0x65, 0x3e, 0x73,
- 0xff, 0x52, 0x3c, 0x73,
+ 0x20, 0x36, 0x5a, 0x7b,
+ 0x00, 0x90, 0x2e, 0x5b,
+ 0xff, 0x65, 0x5a, 0x73,
+ 0xff, 0x52, 0x58, 0x73,
0xff, 0xba, 0xcc, 0x08,
0xff, 0x52, 0x20, 0x09,
0xff, 0x66, 0x74, 0x09,
0xff, 0x65, 0x20, 0x0d,
0xff, 0xba, 0x7e, 0x0c,
- 0x00, 0x6a, 0x3e, 0x5c,
+ 0x00, 0x6a, 0x86, 0x5c,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x51, 0xca, 0x43,
- 0xff, 0x3f, 0x98, 0x73,
+ 0x00, 0x51, 0xe6, 0x43,
+ 0xff, 0x3f, 0xb4, 0x73,
0xff, 0x6a, 0xa2, 0x00,
- 0x00, 0x3f, 0x12, 0x5b,
- 0xff, 0x65, 0x98, 0x73,
+ 0x00, 0x3f, 0x2e, 0x5b,
+ 0xff, 0x65, 0xb4, 0x73,
0x20, 0x36, 0x6c, 0x00,
- 0x20, 0xa0, 0x52, 0x6b,
+ 0x20, 0xa0, 0x6e, 0x6b,
0xff, 0xb9, 0xa2, 0x0c,
0xff, 0x6a, 0xa2, 0x04,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xbe, 0x5b,
+ 0x45, 0x6a, 0xda, 0x5b,
0x01, 0x6a, 0xd0, 0x01,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0x5e, 0x7b,
+ 0x80, 0xeb, 0x7a, 0x7b,
0x01, 0x6a, 0xd6, 0x01,
0x01, 0xe9, 0xa4, 0x34,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xbe, 0x5b,
+ 0x45, 0x6a, 0xda, 0x5b,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x6a, 0x26, 0x01,
- 0x00, 0x65, 0x30, 0x5c,
+ 0x00, 0x65, 0x78, 0x5c,
0xff, 0x99, 0xa4, 0x0c,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xbe, 0x5b,
+ 0x45, 0x6a, 0xda, 0x5b,
0x01, 0x6a, 0xd0, 0x01,
0x01, 0x6a, 0xdc, 0x05,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xbe, 0x5b,
+ 0x45, 0x6a, 0xda, 0x5b,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x01, 0x6a, 0x26, 0x05,
0x01, 0x65, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0x8e, 0x7b,
+ 0x80, 0xee, 0xaa, 0x7b,
0xff, 0x6a, 0xdc, 0x0d,
0xff, 0x65, 0x32, 0x09,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x30, 0x44,
+ 0x00, 0x65, 0x78, 0x44,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0x54, 0x5b,
+ 0x00, 0x6a, 0x70, 0x5b,
0xff, 0x52, 0xa2, 0x0c,
- 0x01, 0x0c, 0x9e, 0x7b,
- 0x04, 0x0c, 0x9e, 0x6b,
+ 0x01, 0x0c, 0xba, 0x7b,
+ 0x04, 0x0c, 0xba, 0x6b,
0xe0, 0x03, 0x06, 0x08,
0xe0, 0x03, 0x7a, 0x0c,
0xff, 0x8c, 0x10, 0x08,
0x00, 0x6c, 0xda, 0x24,
0xff, 0x65, 0xc8, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0xba, 0x5b,
+ 0x41, 0x6a, 0xd6, 0x5b,
0xff, 0x90, 0xe2, 0x09,
0x20, 0x6a, 0xd0, 0x01,
- 0x04, 0x35, 0xdc, 0x7b,
+ 0x04, 0x35, 0xf8, 0x7b,
0x1d, 0x6a, 0xdc, 0x01,
- 0xdc, 0xee, 0xd8, 0x63,
- 0x00, 0x65, 0xe8, 0x43,
+ 0xdc, 0xee, 0xf4, 0x63,
+ 0x00, 0x65, 0x0e, 0x44,
0x01, 0x6a, 0xdc, 0x01,
0x20, 0xa0, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0xe2, 0x7b,
+ 0x80, 0xee, 0xfe, 0x7b,
+ 0x11, 0x6a, 0xdc, 0x01,
+ 0x50, 0xee, 0x02, 0x64,
+ 0x20, 0x6a, 0xd0, 0x01,
+ 0x09, 0x6a, 0xdc, 0x01,
+ 0x88, 0xee, 0x08, 0x64,
0x19, 0x6a, 0xdc, 0x01,
- 0xd8, 0xee, 0xe6, 0x63,
+ 0xd8, 0xee, 0x0c, 0x64,
0xff, 0x6a, 0xdc, 0x09,
- 0x18, 0xee, 0xea, 0x6b,
+ 0x18, 0xee, 0x10, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0x88, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0xba, 0x5b,
+ 0x41, 0x6a, 0xd6, 0x5b,
0x20, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x35, 0x14, 0x6c,
+ 0x04, 0x35, 0x3c, 0x6c,
0xa0, 0x6a, 0xca, 0x00,
0x20, 0x65, 0xc8, 0x18,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
- 0x00, 0x65, 0x00, 0x64,
+ 0x00, 0x65, 0x26, 0x64,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x30, 0x5c,
- 0x04, 0x35, 0x0c, 0x7b,
- 0xa0, 0x6a, 0x20, 0x5c,
- 0x00, 0x65, 0x22, 0x5c,
- 0x00, 0x65, 0x22, 0x5c,
- 0x00, 0x65, 0x22, 0x44,
- 0xff, 0x65, 0xcc, 0x08,
+ 0x00, 0x65, 0x78, 0x44,
+ 0xa0, 0x6a, 0xcc, 0x00,
+ 0xe8, 0x6a, 0xc8, 0x00,
+ 0x01, 0x94, 0x40, 0x6c,
+ 0x10, 0x94, 0x42, 0x6c,
+ 0x08, 0x94, 0x54, 0x6c,
+ 0x08, 0x94, 0x54, 0x6c,
+ 0x08, 0x94, 0x54, 0x6c,
+ 0x00, 0x65, 0x68, 0x5c,
+ 0x08, 0x64, 0xc8, 0x18,
+ 0x00, 0x8c, 0xca, 0x18,
+ 0x00, 0x65, 0x4a, 0x4c,
+ 0x00, 0x65, 0x40, 0x44,
+ 0xf7, 0x93, 0x26, 0x09,
+ 0x08, 0x93, 0x56, 0x6c,
+ 0x00, 0x65, 0x68, 0x5c,
+ 0x08, 0x64, 0xc8, 0x18,
+ 0x08, 0x64, 0x58, 0x64,
+ 0xff, 0x6a, 0xd4, 0x0c,
+ 0x00, 0x65, 0x78, 0x5c,
+ 0x00, 0x65, 0x68, 0x5c,
+ 0x00, 0x65, 0x68, 0x5c,
+ 0x00, 0x65, 0x68, 0x5c,
+ 0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x0c,
- 0x08, 0x94, 0x30, 0x7c,
+ 0x08, 0x94, 0x78, 0x7c,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x34, 0x6c,
+ 0x08, 0x93, 0x7c, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0xff, 0x40, 0x74, 0x09,
0xff, 0x90, 0x80, 0x08,
0xff, 0x6a, 0x72, 0x05,
- 0xff, 0x40, 0x4c, 0x64,
- 0xff, 0x3f, 0x44, 0x64,
+ 0xff, 0x40, 0x94, 0x64,
+ 0xff, 0x3f, 0x8c, 0x64,
0xff, 0x6a, 0xca, 0x04,
0xff, 0x3f, 0x20, 0x09,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0xca, 0x5b,
+ 0x00, 0xb9, 0xe6, 0x5b,
0xff, 0xba, 0x7e, 0x0c,
0xff, 0x40, 0x20, 0x09,
0xff, 0xba, 0x80, 0x0c,
0xff, 0x90, 0x7e, 0x0c,
};
+static int aic7xxx_patch15_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch15_func(struct aic7xxx_host *p)
+{
+ return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
+}
+
+static int aic7xxx_patch14_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch14_func(struct aic7xxx_host *p)
+{
+ return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
+}
+
+static int aic7xxx_patch13_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch13_func(struct aic7xxx_host *p)
+{
+ return ((p->features & AHC_WIDE) != 0);
+}
+
static int aic7xxx_patch12_func(struct aic7xxx_host *p);
static int
aic7xxx_patch12_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_WIDE) != 0);
+ return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
}
static int aic7xxx_patch11_func(struct aic7xxx_host *p);
{ aic7xxx_patch7_func, 113, 1, 2 },
{ aic7xxx_patch0_func, 114, 1, 1 },
{ aic7xxx_patch1_func, 118, 1, 1 },
- { aic7xxx_patch1_func, 121, 3, 2 },
+ { aic7xxx_patch1_func, 121, 3, 3 },
+ { aic7xxx_patch11_func, 123, 1, 1 },
{ aic7xxx_patch0_func, 124, 5, 1 },
- { aic7xxx_patch1_func, 132, 2, 3 },
{ aic7xxx_patch7_func, 132, 1, 1 },
- { aic7xxx_patch0_func, 134, 3, 1 },
- { aic7xxx_patch11_func, 138, 1, 2 },
- { aic7xxx_patch0_func, 139, 1, 1 },
- { aic7xxx_patch7_func, 140, 7, 2 },
- { aic7xxx_patch0_func, 147, 1, 1 },
- { aic7xxx_patch1_func, 152, 14, 3 },
- { aic7xxx_patch11_func, 165, 1, 1 },
- { aic7xxx_patch0_func, 166, 9, 1 },
- { aic7xxx_patch7_func, 180, 2, 1 },
- { aic7xxx_patch7_func, 182, 1, 1 },
- { aic7xxx_patch11_func, 183, 6, 3 },
- { aic7xxx_patch1_func, 183, 2, 2 },
- { aic7xxx_patch0_func, 185, 4, 1 },
- { aic7xxx_patch7_func, 190, 1, 1 },
- { aic7xxx_patch7_func, 194, 20, 1 },
- { aic7xxx_patch1_func, 215, 3, 3 },
- { aic7xxx_patch11_func, 217, 1, 1 },
- { aic7xxx_patch0_func, 218, 5, 1 },
- { aic7xxx_patch11_func, 223, 1, 2 },
- { aic7xxx_patch0_func, 224, 9, 1 },
- { aic7xxx_patch12_func, 240, 1, 2 },
- { aic7xxx_patch0_func, 241, 1, 1 },
- { aic7xxx_patch4_func, 302, 1, 2 },
- { aic7xxx_patch0_func, 303, 1, 1 },
- { aic7xxx_patch2_func, 306, 1, 1 },
- { aic7xxx_patch1_func, 316, 3, 2 },
- { aic7xxx_patch0_func, 319, 5, 1 },
- { aic7xxx_patch12_func, 327, 1, 2 },
- { aic7xxx_patch0_func, 328, 1, 1 },
- { aic7xxx_patch5_func, 333, 1, 1 },
- { aic7xxx_patch11_func, 375, 15, 1 },
- { aic7xxx_patch1_func, 427, 7, 2 },
- { aic7xxx_patch0_func, 434, 8, 1 },
- { aic7xxx_patch1_func, 443, 4, 2 },
- { aic7xxx_patch0_func, 447, 6, 1 },
- { aic7xxx_patch1_func, 453, 4, 2 },
- { aic7xxx_patch0_func, 457, 3, 1 },
- { aic7xxx_patch10_func, 467, 10, 1 },
- { aic7xxx_patch1_func, 486, 17, 4 },
- { aic7xxx_patch9_func, 494, 4, 2 },
- { aic7xxx_patch0_func, 498, 2, 1 },
- { aic7xxx_patch0_func, 503, 33, 1 },
- { aic7xxx_patch10_func, 536, 4, 1 },
- { aic7xxx_patch5_func, 540, 2, 1 },
- { aic7xxx_patch5_func, 543, 9, 1 },
+ { aic7xxx_patch9_func, 133, 1, 1 },
+ { aic7xxx_patch10_func, 134, 3, 1 },
+ { aic7xxx_patch7_func, 137, 3, 2 },
+ { aic7xxx_patch0_func, 140, 2, 1 },
+ { aic7xxx_patch7_func, 142, 5, 2 },
+ { aic7xxx_patch0_func, 147, 3, 1 },
+ { aic7xxx_patch7_func, 150, 1, 2 },
+ { aic7xxx_patch0_func, 151, 2, 1 },
+ { aic7xxx_patch1_func, 153, 15, 4 },
+ { aic7xxx_patch11_func, 166, 1, 2 },
+ { aic7xxx_patch0_func, 167, 1, 1 },
+ { aic7xxx_patch0_func, 168, 10, 1 },
+ { aic7xxx_patch7_func, 181, 1, 2 },
+ { aic7xxx_patch0_func, 182, 2, 1 },
+ { aic7xxx_patch7_func, 184, 18, 1 },
+ { aic7xxx_patch1_func, 202, 3, 3 },
+ { aic7xxx_patch7_func, 204, 1, 1 },
+ { aic7xxx_patch0_func, 205, 4, 1 },
+ { aic7xxx_patch7_func, 210, 2, 1 },
+ { aic7xxx_patch7_func, 215, 13, 3 },
+ { aic7xxx_patch12_func, 218, 1, 1 },
+ { aic7xxx_patch12_func, 219, 4, 1 },
+ { aic7xxx_patch1_func, 229, 3, 3 },
+ { aic7xxx_patch11_func, 231, 1, 1 },
+ { aic7xxx_patch0_func, 232, 5, 1 },
+ { aic7xxx_patch11_func, 237, 1, 2 },
+ { aic7xxx_patch0_func, 238, 9, 1 },
+ { aic7xxx_patch13_func, 254, 1, 2 },
+ { aic7xxx_patch0_func, 255, 1, 1 },
+ { aic7xxx_patch4_func, 316, 1, 2 },
+ { aic7xxx_patch0_func, 317, 1, 1 },
+ { aic7xxx_patch2_func, 320, 1, 1 },
+ { aic7xxx_patch1_func, 330, 3, 2 },
+ { aic7xxx_patch0_func, 333, 5, 1 },
+ { aic7xxx_patch13_func, 341, 1, 2 },
+ { aic7xxx_patch0_func, 342, 1, 1 },
+ { aic7xxx_patch5_func, 347, 1, 1 },
+ { aic7xxx_patch11_func, 389, 15, 2 },
+ { aic7xxx_patch14_func, 402, 1, 1 },
+ { aic7xxx_patch1_func, 441, 7, 2 },
+ { aic7xxx_patch0_func, 448, 8, 1 },
+ { aic7xxx_patch1_func, 457, 4, 2 },
+ { aic7xxx_patch0_func, 461, 6, 1 },
+ { aic7xxx_patch1_func, 467, 4, 2 },
+ { aic7xxx_patch0_func, 471, 3, 1 },
+ { aic7xxx_patch10_func, 481, 10, 1 },
+ { aic7xxx_patch1_func, 500, 22, 5 },
+ { aic7xxx_patch11_func, 508, 4, 1 },
+ { aic7xxx_patch7_func, 512, 7, 3 },
+ { aic7xxx_patch15_func, 512, 5, 2 },
+ { aic7xxx_patch0_func, 517, 2, 1 },
+ { aic7xxx_patch10_func, 522, 50, 3 },
+ { aic7xxx_patch14_func, 543, 17, 2 },
+ { aic7xxx_patch0_func, 560, 4, 1 },
+ { aic7xxx_patch10_func, 572, 4, 1 },
+ { aic7xxx_patch5_func, 576, 2, 1 },
+ { aic7xxx_patch5_func, 579, 9, 1 },
};
unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD];
unsigned char scsi_cur_buff = 1; /* Leave space for command buffer */
__u32 esp_virt_buffer;
-int scsi_current_length = 0;
+int scsi_current_length;
volatile unsigned char cmd_buffer[16];
volatile unsigned char pmaz_cmd_buffer[16];
esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer);
esp->irq = SCSI_INT;
- request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI",
- NULL);
- request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA",
- NULL);
+ if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ "NCR 53C94 SCSI", NULL))
+ goto err_dealloc;
+ if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT,
+ "JUNKIO SCSI DMA", NULL))
+ goto err_free_irq;
+
esp->scsi_id = 7;
esp->dma_mmu_release_scsi_sgl = 0;
esp->dma_advance_sg = 0;
- request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ_AA", NULL);
+ if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ "PMAZ_AA", NULL)) {
+ esp_deallocate(esp);
+ release_tc_card(slot);
+ continue;
+ }
esp->scsi_id = 7;
esp->diff = 0;
esp_initialize(esp);
if(nesps) {
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
- esps_running = esps_in_use;
- return esps_in_use;
- } else
- return 0;
+ esps_running = esps_in_use;
+ return esps_in_use;
+ }
+ return 0;
+
+ err_free_irq:
+ free_irq(esp->irq, esp_intr);
+ err_dealloc:
+ esp_deallocate(esp);
+ return 0;
}
/************************************************************* DMA Functions */
(char *) KSEG0ADDR((sp->request_buffer));
}
-#endif
\ No newline at end of file
+#endif
retval->use_clustering = tpnt->use_clustering;
retval->select_queue_depths = tpnt->select_queue_depths;
+ retval->max_sectors = tpnt->max_sectors;
if(!scsi_hostlist)
scsi_hostlist = retval;
*/
short unsigned int sg_tablesize;
+ /*
+ * if the host adapter has limitations beside segment count
+ */
+ short unsigned int max_sectors;
+
/*
* True if this host adapter can make good use of linked commands.
* This will allow more than one command to be queued to a given
int can_queue;
short cmd_per_lun;
short unsigned int sg_tablesize;
+ short unsigned int max_sectors;
unsigned in_recovery:1;
unsigned unchecked_isa_dma:1;
/* These are used by loadable modules */
extern int scsi_register_module(int, void *);
-extern void scsi_unregister_module(int, void *);
+extern int scsi_unregister_module(int, void *);
/* The different types of modules that we can load and unload */
#define MODULE_SCSI_HA 1
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3-20010212"
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3b-20010512"
#define SCSI_NCR_DEBUG_FLAGS (0)
};
/*
-** Print something which allows to retrieve the controler type, unit,
+** Print something which allows to retrieve the controller type, unit,
** target, lun concerned by a kernel message.
*/
**
**----------------------------------------------------
*/
-#if 0 /* This stuff was only usefull for linux-1.2.13 */
+#if 0 /* This stuff was only useful for linux-1.2.13 */
if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
lp->numtags = tp->usrtags;
ncr_setup_tags (np, cmd->target, cmd->lun);
*/
fak = (kpc - 1) / div_10M[div] + 1;
-#if 0 /* This optimization does not seem very usefull */
+#if 0 /* This optimization does not seem very useful */
per = (fak * div_10M[div]) / clk;
delta=(INB (nc_dfifo) - rest) & 0x7f;
/*
- ** The data in the dma fifo has not been transfered to
+ ** The data in the dma fifo has not been transferred to
** the target -> add the amount to the rest
** and clear the data.
** Check the sstat2 register in case of wide transfer.
** Was Sie schon immer ueber transfermode negotiation wissen wollten ...
**
** We try to negotiate sync and wide transfer only after
-** a successfull inquire command. We look at byte 7 of the
+** a successful inquire command. We look at byte 7 of the
** inquire data to determine the capabilities of the target.
**
** When we try to negotiate, we append the negotiation message
/*==========================================================
**
**
-** Aquire a control block
+** Acquire a control block
**
**
**==========================================================
}
host->this_id = hostdata->host_param.initiator_scsi_id;
+ host->max_sectors = 64;
if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
"qlogicisp", host))
prom_getintdefault(qpti->sdev->bus->prom_node,
"scsi-initiator-id", 7);
qpti->qhost->this_id = qpti->scsi_id;
+ qpti->qhost->max_sectors = 64;
printk("SCSI ID %d ", qpti->scsi_id);
}
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#define __KERNEL_SYSCALLS__
* the response. We treat it as if the command never finished.
*
* Since serial_number is now 0, the error handler cound detect this
- * situation and avoid to call the the low level driver abort routine.
+ * situation and avoid to call the low level driver abort routine.
* (DB)
*
* FIXME(eric) - I believe that this test is now redundant, due to
}
static int scsi_register_host(Scsi_Host_Template *);
-static void scsi_unregister_host(Scsi_Host_Template *);
+static int scsi_unregister_host(Scsi_Host_Template *);
/*
* Function: scsi_release_commandblocks()
if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
return -ENOMEM;
- copy_from_user(buffer, buf, length);
+ if(copy_from_user(buffer, buf, length))
+ {
+ err =-EFAULT;
+ goto out;
+ }
err = -EINVAL;
+
if (length < PAGE_SIZE)
- buffer[length] ='\0';
- else if (buffer[length])
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
goto out;
if (length < 11 || strncmp("scsi", buffer, 4))
return 1; /* Must be already loaded, or
* no detect routine available
*/
+
+ /* If max_sectors isn't set, default to max */
+ if (!tpnt->max_sectors)
+ tpnt->max_sectors = MAX_SECTORS;
+
pcount = next_scsi_host;
/* The detect routine must carefully spinunlock/spinlock if
/*
* Similarly, this entry point should be called by a loadable module if it
* is trying to remove a low level scsi driver from the system.
- *
- * Note - there is a fatal flaw in the deregister module function.
- * There is no way to return a code that says 'I cannot be unloaded now'.
- * The system relies entirely upon usage counts that are maintained,
- * and the assumption is that if the usage count is 0, then the module
- * can be unloaded.
*/
-static void scsi_unregister_host(Scsi_Host_Template * tpnt)
+static int scsi_unregister_host(Scsi_Host_Template * tpnt)
{
int online_status;
int pcount0, pcount;
struct Scsi_Host *shpnt;
char name[10]; /* host_no>=10^9? I don't think so. */
+ /* get the big kernel lock, so we don't race with open() */
+ lock_kernel();
+
/*
* First verify that this host adapter is completely free with no pending
* commands
if (SDpnt->host->hostt == tpnt
&& SDpnt->host->hostt->module
&& GET_USE_COUNT(SDpnt->host->hostt->module))
- return;
+ goto err_out;
/*
* FIXME(eric) - We need to find a way to notify the
* low level driver that we are shutting down - via the
}
SDpnt->online = online_status;
printk(KERN_ERR "Device busy???\n");
- return;
+ goto err_out;
}
/*
* No, this device is really free. Mark it as such, and
/* If something still attached, punt */
if (SDpnt->attached) {
printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached);
- return;
+ goto err_out;
}
devfs_unregister (SDpnt->de);
}
}
}
MOD_DEC_USE_COUNT;
+
+ unlock_kernel();
+ return 0;
+
+err_out:
+ unlock_kernel();
+ return -1;
}
static int scsi_unregister_device(struct Scsi_Device_Template *tpnt);
struct Scsi_Host *shpnt;
struct Scsi_Device_Template *spnt;
struct Scsi_Device_Template *prev_spnt;
-
+
+ lock_kernel();
/*
* If we are busy, this is not going to fly.
*/
if (GET_USE_COUNT(tpnt->module) != 0)
- return 0;
+ goto error_out;
/*
* Next, detach the devices from the driver.
prev_spnt->next = spnt->next;
MOD_DEC_USE_COUNT;
+ unlock_kernel();
/*
* Final cleanup for the driver is done in the driver sources in the
* cleanup function.
*/
return 0;
+error_out:
+ unlock_kernel();
+ return -1;
}
/* Reverse the actions taken above
*/
-void scsi_unregister_module(int module_type, void *ptr)
+int scsi_unregister_module(int module_type, void *ptr)
{
+ int retval = 0;
+
switch (module_type) {
case MODULE_SCSI_HA:
- scsi_unregister_host((Scsi_Host_Template *) ptr);
+ retval = scsi_unregister_host((Scsi_Host_Template *) ptr);
break;
case MODULE_SCSI_DEV:
- scsi_unregister_device((struct Scsi_Device_Template *) ptr);
- break;
+ retval = scsi_unregister_device((struct Scsi_Device_Template *)ptr);
+ break;
/* The rest of these are not yet implemented. */
case MODULE_SCSI_CONST:
case MODULE_SCSI_IOCTL:
- default:
break;
+ default:;
}
- return;
+ return retval;
}
#ifdef CONFIG_PROC_FS
unsigned remap:1; /* support remapping */
unsigned starved:1; /* unable to process commands because
host busy */
+
+ // Flag to allow revalidate to succeed in sd_open
+ int allow_revalidate;
};
unsigned short sr_use_sg; /* Number of pieces of scatter-gather */
unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */
unsigned sr_underflow; /* Return error if less than
- this amount is transfered */
+ this amount is transferred */
};
/*
void *buffer; /* Data buffer */
unsigned underflow; /* Return error if less than
- this amount is transfered */
+ this amount is transferred */
unsigned old_underflow; /* save underflow here when reusing the
* command for error handling */
memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
sizeof(generic_sense));
- SCpnt->cmnd[1] = SCpnt->lun << 5;
+ if (SCpnt->device->scsi_level <= SCSI_2)
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
memcpy((void *) SCpnt->cmnd, (void *) tur_command,
sizeof(tur_command));
- SCpnt->cmnd[1] = SCpnt->lun << 5;
+ if (SCpnt->device->scsi_level <= SCSI_2)
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
/*
* Zero the sense buffer. The SCSI spec mandates that any
SCpnt->device->expecting_cc_ua = 0;
return NEEDS_RETRY;
}
+ /*
+ * If the device is in the process of becoming ready, we
+ * should retry.
+ */
+ if ((SCpnt->sense_buffer[12] == 0x04) &&
+ (SCpnt->sense_buffer[13] == 0x01)) {
+ return NEEDS_RETRY;
+ }
return SUCCESS;
/* these three are not supported */
*
* *(char *) ((int *) arg)[2] the actual command byte.
*
- * Note that if more than MAX_BUF bytes are requested to be transfered,
+ * Note that if more than MAX_BUF bytes are requested to be transferred,
* the ioctl will fail with error EINVAL. MAX_BUF can be increased in
* the future by increasing the size that scsi_malloc will accept.
*
Scsi_Request *SRpnt;
Scsi_Device *SDpnt;
unsigned char opcode;
- int inlen, outlen, cmdlen;
- int needed, buf_needed;
+ unsigned int inlen, outlen, cmdlen;
+ unsigned int needed, buf_needed;
int timeout, retries, result;
int data_direction;
if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
return -EFAULT;
- __get_user(inlen, &sic->inlen);
- __get_user(outlen, &sic->outlen);
+ if(__get_user(inlen, &sic->inlen))
+ return -EFAULT;
+
+ if(__get_user(outlen, &sic->outlen))
+ return -EFAULT;
/*
* We do not transfer more than MAX_BUF with this interface.
return -EINVAL;
cmd_in = sic->data;
- __get_user(opcode, cmd_in);
+ if(get_user(opcode, cmd_in))
+ return -EFAULT;
needed = buf_needed = (inlen > outlen ? inlen : outlen);
if (buf_needed) {
* Obtain the command from the user's address space.
*/
cmdlen = COMMAND_SIZE(opcode);
+
+ result = -EFAULT;
if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen))
- return -EFAULT;
+ goto error;
- __copy_from_user(cmd, cmd_in, cmdlen);
+ if(__copy_from_user(cmd, cmd_in, cmdlen))
+ goto error;
/*
* Obtain the data to be sent to the device (if any).
*/
- __copy_from_user(buf, cmd_in + cmdlen, inlen);
+
+ if(copy_from_user(buf, cmd_in + cmdlen, inlen))
+ goto error;
/*
* Set the lun field to the correct value.
*/
- cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
+ if (dev->scsi_level <= SCSI_2)
+ cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
switch (opcode) {
case FORMAT_UNIT:
SRpnt = scsi_allocate_request(dev);
if( SRpnt == NULL )
{
- return -EINTR;
+ result = -EINTR;
+ goto error;
}
SRpnt->sr_data_direction = data_direction;
/*
* If there was an error condition, pass the info back to the user.
*/
+
result = SRpnt->sr_result;
+
if (SRpnt->sr_result) {
int sb_len = sizeof(SRpnt->sr_sense_buffer);
} else {
if (copy_to_user(cmd_in, buf, outlen))
result = -EFAULT;
- }
+ }
SDpnt = SRpnt->sr_device;
scsi_release_request(SRpnt);
SRpnt = NULL;
+error:
if (buf)
scsi_free(buf, buf_needed);
int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
{
char scsi_cmd[MAX_COMMAND_SIZE];
+ char cmd_byte1;
/* No idea how this happens.... */
if (!dev)
if (!scsi_block_when_processing_errors(dev)) {
return -ENODEV;
}
+ cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
+
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun)))
return -EFAULT;
- __put_user(dev->id
- + (dev->lun << 8)
- + (dev->channel << 16)
+ __put_user((dev->id & 0xff)
+ + ((dev->lun & 0xff) << 8)
+ + ((dev->channel & 0xff) << 16)
+ ((dev->host->host_no & 0xff) << 24),
&((Scsi_Idlun *) arg)->dev_id);
__put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
if (!dev->removable || !dev->lockable)
return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
- scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[1] = cmd_byte1;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
if (!dev->removable || !dev->lockable)
return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
- scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[1] = cmd_byte1;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
case SCSI_IOCTL_TEST_UNIT_READY:
scsi_cmd[0] = TEST_UNIT_READY;
- scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[1] = cmd_byte1;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = 0;
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
break;
case SCSI_IOCTL_START_UNIT:
scsi_cmd[0] = START_STOP;
- scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[1] = cmd_byte1;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = 1;
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
break;
case SCSI_IOCTL_STOP_UNIT:
scsi_cmd[0] = START_STOP;
- scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[1] = cmd_byte1;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = 0;
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
nsect = bh->b_size >> 9;
blk_finished_io(nsect);
req->bh = bh->b_reqnext;
- req->nr_sectors -= nsect;
- req->sector += nsect;
bh->b_reqnext = NULL;
sectors -= nsect;
bh->b_end_io(bh, uptodate);
if ((bh = req->bh) != NULL) {
+ req->hard_sector += nsect;
+ req->hard_nr_sectors -= nsect;
+ req->sector += nsect;
+ req->nr_sectors -= nsect;
+
req->current_nr_sectors = bh->b_size >> 9;
if (req->nr_sectors < req->current_nr_sectors) {
req->nr_sectors = req->current_nr_sectors;
max_segments = 64;
#endif
+ if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
+ return 0;
+
if (use_clustering) {
/*
* See if we can do this without creating another
max_segments = 64;
#endif
+ if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
+ return 0;
+
if (use_clustering) {
/*
* See if we can do this without creating another
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
+ /*
+ * First check if the either of the requests are re-queued
+ * requests. Can't merge them if they are.
+ */
+ if (req->special || next->special)
+ return 0;
+
SDpnt = (Scsi_Device *) q->queuedata;
SHpnt = SDpnt->host;
return 0;
}
#endif
+
+ if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors)
+ return 0;
+
/*
* The main question is whether the two segments at the boundaries
* would be considered one or two.
memset((void *) SCpnt->sense_buffer, 0,
sizeof(SCpnt->sense_buffer));
- SCpnt->cmnd[1] = SCpnt->lun << 5;
+ if (SCpnt->device->scsi_level <= SCSI_2)
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
SCpnt->request_buffer = &SCpnt->sense_buffer;
#define BLIST_ISROM 0x200
static void print_inquiry(unsigned char *data);
-static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
- int *sparse_lun, Scsi_Device ** SDpnt,
- struct Scsi_Host *shpnt, char *scsi_result);
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+ unsigned int lun, int lun0_scsi_level,
+ unsigned int *max_scsi_dev, unsigned int *sparse_lun,
+ Scsi_Device ** SDpnt, struct Scsi_Host *shpnt,
+ char *scsi_result);
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+ struct Scsi_Host *shpnt);
struct dev_info {
const char *vendor;
{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
{"DEC","HSG80","*", BLIST_FORCELUN},
{"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
+ {"COMPAQ","CR3500","*", BLIST_FORCELUN},
{"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
{"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
{"MegaRAID", "LD", "*", BLIST_FORCELUN},
{"DGC", "RAID", "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0)
{"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0)
+ {"DELL", "PV660F", "*", BLIST_SPARSELUN},
+ {"DELL", "PV660F PSEUDO", "*", BLIST_SPARSELUN},
+ {"DELL", "PSEUDO DEVICE .", "*", BLIST_SPARSELUN}, // Dell PV 530F
{"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F
+ {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN},
{"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders
{"DELL", "PERCRAID", "*", BLIST_FORCELUN},
{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
{NULL, NULL, NULL}
};
+#define MAX_SCSI_LUNS 0xFFFFFFFF
+
#ifdef CONFIG_SCSI_MULTI_LUN
-static int max_scsi_luns = 8;
+static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
#else
-static int max_scsi_luns = 1;
+static unsigned int max_scsi_luns = 1;
#endif
#ifdef MODULE
MODULE_PARM(max_scsi_luns, "i");
-MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)");
+MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
#else
static int __init scsi_luns_setup(char *str)
{
- int tmp;
+ unsigned int tmp;
if (get_option(&str, &tmp) == 1) {
max_scsi_luns = tmp;
return 1;
} else {
printk("scsi_luns_setup : usage max_scsi_luns=n "
- "(n should be between 1 and 8)\n");
+ "(n should be between 1 and 2^32-1)\n");
return 0;
}
}
uint hlun)
{
uint channel;
- int dev;
- int lun;
- int max_dev_lun;
+ unsigned int dev;
+ unsigned int lun;
+ unsigned int max_dev_lun;
unsigned char *scsi_result;
unsigned char scsi_result0[256];
Scsi_Device *SDpnt;
Scsi_Device *SDtail;
- int sparse_lun;
+ unsigned int sparse_lun;
+ int lun0_sl;
scsi_result = NULL;
lun = hlun;
if (lun >= shpnt->max_lun)
goto leave;
- scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun,
- &SDpnt, shpnt, scsi_result);
+ if ((0 == lun) || (lun > 7))
+ lun0_sl = SCSI_3; /* actually don't care for 0 == lun */
+ else
+ lun0_sl = find_lun0_scsi_level(channel, dev, shpnt);
+ scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun,
+ &sparse_lun, &SDpnt, shpnt, scsi_result);
if (SDpnt != oldSDpnt) {
/* it could happen the blockdevice hasn't yet been inited */
max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
max_scsi_luns : shpnt->max_lun);
sparse_lun = 0;
- for (lun = 0; lun < max_dev_lun; ++lun) {
- if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,
- &sparse_lun, &SDpnt, shpnt,
- scsi_result)
+ for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) {
+ if (!scan_scsis_single(channel, order_dev, lun, lun0_sl,
+ &max_dev_lun, &sparse_lun, &SDpnt, shpnt,
+ scsi_result)
&& !sparse_lun)
break; /* break means don't probe further for luns!=0 */
+ if (SDpnt && (0 == lun))
+ lun0_sl = SDpnt->scsi_level;
} /* for lun ends */
} /* if this_id != id ends */
} /* for dev ends */
* Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
* Global variables used : scsi_devices(linked list)
*/
-static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
- int *sparse_lun, Scsi_Device ** SDpnt2,
- struct Scsi_Host *shpnt, char *scsi_result)
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+ unsigned int lun, int lun0_scsi_level,
+ unsigned int *max_dev_lun, unsigned int *sparse_lun,
+ Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt,
+ char *scsi_result)
{
char devname[64];
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
* Build an INQUIRY command block.
*/
scsi_cmd[0] = INQUIRY;
- scsi_cmd[1] = (lun << 5) & 0xe0;
+ if ((lun > 0) && (lun0_scsi_level <= SCSI_2))
+ scsi_cmd[1] = (lun << 5) & 0xe0;
+ else
+ scsi_cmd[1] = 0; /* SCSI_3 and higher, don't touch */
scsi_cmd[2] = 0;
scsi_cmd[3] = 0;
scsi_cmd[4] = 255;
printk("Unlocked floptical drive.\n");
SDpnt->lockable = 0;
scsi_cmd[0] = MODE_SENSE;
- scsi_cmd[1] = (lun << 5) & 0xe0;
+ if (shpnt->max_lun <= 8)
+ scsi_cmd[1] = (lun << 5) & 0xe0;
+ else scsi_cmd[1] = 0; /* any other idea? */
scsi_cmd[2] = 0x2e;
scsi_cmd[3] = 0;
scsi_cmd[4] = 0x2a;
* other settings, and scan all of them.
*/
if (bflags & BLIST_SPARSELUN) {
- *max_dev_lun = 8;
+ /*
+ * Scanning MAX_SCSI_LUNS units would be a bad idea.
+ * Any better idea?
+ * I think we need REPORT LUNS in future to avoid scanning
+ * of unused LUNs. But, that is another item.
+ *
+ * FIXME(eric) - perhaps this should be a kernel configurable?
+ */
+ if (*max_dev_lun < shpnt->max_lun)
+ *max_dev_lun = shpnt->max_lun;
+ else if ((max_scsi_luns >> 1) >= *max_dev_lun)
+ *max_dev_lun += shpnt->max_lun;
+ else *max_dev_lun = max_scsi_luns;
*sparse_lun = 1;
return 1;
}
* settings, and scan all of them.
*/
if (bflags & BLIST_FORCELUN) {
- *max_dev_lun = 8;
+ /*
+ * Scanning MAX_SCSI_LUNS units would be a bad idea.
+ * Any better idea?
+ * I think we need REPORT LUNS in future to avoid scanning
+ * of unused LUNs. But, that is another item.
+ */
+ if (*max_dev_lun < shpnt->max_lun)
+ *max_dev_lun = shpnt->max_lun;
+ else if ((max_scsi_luns >> 1) >= *max_dev_lun)
+ *max_dev_lun += shpnt->max_lun;
+ else *max_dev_lun = max_scsi_luns;
return 1;
}
/*
return 1;
}
+/*
+ * The worker for scan_scsis.
+ * Returns the scsi_level of lun0 on this host, channel and dev (if already
+ * known), otherwise returns SCSI_2.
+ */
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+ struct Scsi_Host *shpnt)
+{
+ int res = SCSI_2;
+ Scsi_Device *SDpnt;
+
+ for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ if ((0 == SDpnt->lun) && (dev == SDpnt->id) &&
+ (channel == SDpnt->channel))
+ return (int)SDpnt->scsi_level;
+ }
+ /* haven't found lun0, should send INQUIRY but take easy route */
+ return res;
+}
*
* Modified by Torben Mathiasen tmm@image.dk
* Resource allocation fixes in sd_init and cleanups.
+ *
+ * Modified by Alex Davis <letmein@erols.com>
+ * Fix problem where partition info not being read in sd_open.
+ *
+ * Modified by Alex Davis <letmein@erols.com>
+ * Fix problem where removable media could be ejected after sd_open.
*/
#include <linux/config.h>
(SCpnt->request.cmd == WRITE) ? "writing" : "reading",
this_count, SCpnt->request.nr_sectors));
- SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;
+ SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+ ((SCpnt->lun << 5) & 0xe0) : 0;
if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) {
if (this_count > 0xffff)
static int sd_open(struct inode *inode, struct file *filp)
{
- int target;
+ int target, retval = -ENXIO;
Scsi_Device * SDev;
target = DEVICE_NR(inode->i_rdev);
while (rscsi_disks[target].device->busy)
barrier();
+ /*
+ * The following code can sleep.
+ * Module unloading must be prevented
+ */
+ SDev = rscsi_disks[target].device;
+ if (SDev->host->hostt->module)
+ __MOD_INC_USE_COUNT(SDev->host->hostt->module);
+ if (sd_template.module)
+ __MOD_INC_USE_COUNT(sd_template.module);
+ SDev->access_count++;
+
if (rscsi_disks[target].device->removable) {
+ SDev->allow_revalidate = 1;
check_disk_change(inode->i_rdev);
+ SDev->allow_revalidate = 0;
/*
* If the drive is empty, just let the open fail.
*/
- if (!rscsi_disks[target].ready)
- return -ENXIO;
+ if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) {
+ retval = -ENOMEDIUM;
+ goto error_out;
+ }
/*
* Similarly, if the device has the write protect tab set,
* have the open fail if the user expects to be able to write
* to the thing.
*/
- if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2))
- return -EROFS;
+ if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) {
+ retval = -EROFS;
+ goto error_out;
+ }
}
- SDev = rscsi_disks[target].device;
/*
* It is possible that the disk changing stuff resulted in the device
* being taken offline. If this is the case, report this to the user,
* the open actually succeeded.
*/
if (!SDev->online) {
- return -ENXIO;
+ goto error_out;
}
/*
* See if we are requesting a non-existent partition. Do this
* after checking for disk change.
*/
- if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
- return -ENXIO;
+ if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) {
+ goto error_out;
+ }
if (SDev->removable)
- if (!SDev->access_count)
+ if (SDev->access_count==1)
if (scsi_block_when_processing_errors(SDev))
scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
- SDev->access_count++;
+
+ return 0;
+
+error_out:
+ SDev->access_count--;
if (SDev->host->hostt->module)
- __MOD_INC_USE_COUNT(SDev->host->hostt->module);
+ __MOD_DEC_USE_COUNT(SDev->host->hostt->module);
if (sd_template.module)
- __MOD_INC_USE_COUNT(sd_template.module);
- return 0;
+ __MOD_DEC_USE_COUNT(sd_template.module);
+ return retval;
}
static int sd_release(struct inode *inode, struct file *file)
while (retries < 3) {
cmd[0] = TEST_UNIT_READY;
- cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+ ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
memset((void *) &cmd[2], 0, 8);
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
if (!spintime) {
printk("%s: Spinning up disk...", nbuff);
cmd[0] = START_STOP;
- cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+ ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
cmd[1] |= 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
retries = 3;
do {
cmd[0] = READ_CAPACITY;
- cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+ ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
memset((void *) &cmd[2], 0, 8);
memset((void *) buffer, 0, 8);
SRpnt->sr_cmd_len = 0;
memset((void *) &cmd[0], 0, 8);
cmd[0] = MODE_SENSE;
- cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+ ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
cmd[2] = 0x3f; /* Get all pages */
cmd[4] = 8; /* But we only want the 8 byte header */
SRpnt->sr_cmd_len = 0;
static int sd_detect(Scsi_Device * SDp)
{
- char nbuff[6];
if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
return 0;
-
- sd_devname(sd_template.dev_noticed++, nbuff);
- printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
- SDp->removable ? "removable " : "",
- nbuff,
- SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+ sd_template.dev_noticed++;
return 1;
}
unsigned int devnum;
Scsi_Disk *dpnt;
int i;
+ char nbuff[6];
if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
return 0;
SD_GENDISK(i).de_arr[devnum] = SDp->de;
if (SDp->removable)
SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE;
+ sd_devname(i, nbuff);
+ printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
+ SDp->removable ? "removable " : "",
+ nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
return 0;
}
#define DEVICE_BUSY rscsi_disks[target].device->busy
+#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate
#define USAGE rscsi_disks[target].device->access_count
#define CAPACITY rscsi_disks[target].capacity
#define MAYBE_REINIT sd_init_onedisk(target)
target = DEVICE_NR(dev);
- if (DEVICE_BUSY || USAGE > maxusage) {
+ if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) {
printk("Device busy for revalidation (usage=%d)\n", USAGE);
return -EBUSY;
}
static int *sr_sizes;
static int *sr_blocksizes;
+static int *sr_hardsizes;
static int sr_open(struct cdrom_device_info *, int);
void get_sectorsize(int);
static int sr_scatter_pad(Scsi_Cmnd *SCpnt, int s_size)
{
struct scatterlist *sg, *old_sg = NULL;
- int i, fsize, bsize, sg_ent;
+ int i, fsize, bsize, sg_ent, sg_count;
char *front, *back;
back = front = NULL;
/*
* extend or allocate new scatter-gather table
*/
- if (SCpnt->use_sg)
+ sg_count = SCpnt->use_sg;
+ if (sg_count)
old_sg = (struct scatterlist *) SCpnt->request_buffer;
else {
- SCpnt->use_sg = 1;
+ sg_count = 1;
sg_ent++;
}
- SCpnt->sglist_len = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511;
- if ((sg = scsi_malloc(SCpnt->sglist_len)) == NULL)
+ i = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511;
+ if ((sg = scsi_malloc(i)) == NULL)
goto no_mem;
+ /*
+ * no more failing memory allocs possible, we can safely assign
+ * SCpnt values now
+ */
+ SCpnt->sglist_len = i;
+ SCpnt->use_sg = sg_count;
memset(sg, 0, SCpnt->sglist_len);
i = 0;
static int sr_init_command(Scsi_Cmnd * SCpnt)
{
- int dev, devm, block, this_count, s_size;
+ int dev, devm, block=0, this_count, s_size;
devm = MINOR(SCpnt->request.rq_dev);
dev = DEVICE_NR(SCpnt->request.rq_dev);
- SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d\n", devm));
+ SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
if (dev >= sr_template.nr_dev ||
!scsi_CDs[dev].device ||
(SCpnt->request.cmd == WRITE) ? "writing" : "reading",
this_count, SCpnt->request.nr_sectors));
- SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0;
+ SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+ ((SCpnt->lun << 5) & 0xe0) : 0;
if (this_count > 0xffff)
this_count = 0xffff;
if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
return 0;
-
- printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
- sr_template.dev_noticed++,
- SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+ sr_template.dev_noticed++;
return 1;
}
sr_template.nr_dev++;
if (sr_template.nr_dev > sr_template.dev_max)
panic("scsi_devices corrupt (sr)");
+
+ printk("Attached scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
+ i, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
return 0;
}
retries = 3;
do {
cmd[0] = READ_CAPACITY;
- cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+ cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
memset((void *) &cmd[2], 0, 8);
SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */
SRpnt->sr_cmd_len = 0;
} else {
#if 0
if (cdrom_get_last_written(MKDEV(MAJOR_NR, i),
- (long *) &scsi_CDs[i].capacity))
+ &scsi_CDs[i].capacity))
#endif
scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
(buffer[1] << 16) |
};
buffer = (unsigned char *) scsi_malloc(512);
+ if (!buffer)
+ {
+ printk(KERN_ERR "sr: out of memory.\n");
+ return;
+ }
cmd[0] = MODE_SENSE;
- cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+ cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
cmd[2] = 0x2a;
cmd[4] = 128;
cmd[3] = cmd[5] = 0;
Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
/* set the LUN */
- cgc->cmd[1] |= device->lun << 5;
+ if (device->scsi_level <= SCSI_2)
+ cgc->cmd[1] |= device->lun << 5;
cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
if (!sr_blocksizes)
goto cleanup_sizes;
+ sr_hardsizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
+ if (!sr_hardsizes)
+ goto cleanup_blocksizes;
/*
* These are good guesses for the time being.
- * Don't set sr_hardsizes here! That will prevent reading anything smaller.
*/
for (i = 0; i < sr_template.dev_max; i++) {
sr_blocksizes[i] = 2048;
+ sr_hardsizes[i] = 2048;
}
blksize_size[MAJOR_NR] = sr_blocksizes;
+ hardsect_size[MAJOR_NR] = sr_hardsizes;
return 0;
-
+cleanup_blocksizes:
+ kfree(sr_blocksizes);
cleanup_sizes:
kfree(sr_sizes);
cleanup_cds:
scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i);
scsi_CDs[i].cdi.mask = 0;
scsi_CDs[i].cdi.capacity = 1;
+ /*
+ * FIXME: someone needs to handle a get_capabilities
+ * failure properly ??
+ */
get_capabilities(i);
sr_vendor_init(i);
kfree(sr_blocksizes);
sr_blocksizes = NULL;
+ kfree(sr_hardsizes);
+ sr_hardsizes = NULL;
}
blksize_size[MAJOR_NR] = NULL;
+ hardsect_size[MAJOR_NR] = NULL;
blk_size[MAJOR_NR] = NULL;
read_ahead[MAJOR_NR] = 0;
u_char sr_cmd[10];
sr_cmd[0] = GPCMD_TEST_UNIT_READY;
- sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
+ sr_cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[minor].device->lun) << 5) : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL);
}
u_char sr_cmd[10];
sr_cmd[0] = GPCMD_START_STOP_UNIT;
- sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+ sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
int result;
sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
- sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+ sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
sr_cmd[2] = 0x40; /* I do want the subchannel info */
sr_cmd[3] = 0x02; /* Give me medium catalog number info */
sr_cmd[4] = sr_cmd[5] = 0;
memset(sr_cmd, 0, MAX_COMMAND_SIZE);
sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */
- sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5;
+ sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0;
sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
sr_cmd[3] = speed & 0xff; /* LSB */
struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
- sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
+ sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[target].device->lun) << 5) : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
sr_cmd[8] = 12; /* LSB of length */
struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
- sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
- (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
+ sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+ ((scsi_CDs[target].device->lun) << 5) : 0;
+ sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
sr_cmd[6] = tocentry->cdte_track;
sr_cmd[8] = 12; /* LSB of length */
struct cdrom_ti* ti = (struct cdrom_ti*)arg;
sr_cmd[0] = GPCMD_PLAYAUDIO_TI;
- sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+ sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[target].device->lun << 5) : 0;
sr_cmd[4] = ti->cdti_trk0;
sr_cmd[5] = ti->cdti_ind0;
sr_cmd[7] = ti->cdti_trk1;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = GPCMD_READ_CD; /* READ_CD */
- cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
+ cmd[1] |= ((format & 7) << 2);
cmd[2] = (unsigned char) (lba >> 24) & 0xff;
cmd[3] = (unsigned char) (lba >> 16) & 0xff;
cmd[4] = (unsigned char) (lba >> 8) & 0xff;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = GPCMD_READ_10;
- cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
cmd[2] = (unsigned char) (lba >> 24) & 0xff;
cmd[3] = (unsigned char) (lba >> 16) & 0xff;
cmd[4] = (unsigned char) (lba >> 8) & 0xff;
target = MINOR(cdi->dev);
switch (cmd) {
+ case BLKGETSIZE:
+ return put_user(scsi_CDs[target].capacity >> 1, (long *) arg);
case BLKROSET:
case BLKROGET:
case BLKRASET:
#endif
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
- cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
+ cmd[1] |= (1 << 4);
cmd[4] = 12;
modesel = (struct ccs_modesel_head *) buffer;
memset(modesel, 0, sizeof(*modesel));
case VENDOR_SCSI3:
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_TOC;
- cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
cmd[8] = 12;
cmd[9] = 0x40;
rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
unsigned long min, sec, frame;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = 0xde;
- cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
+ cmd[1] |= 0x03;
cmd[2] = 0xb0;
rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
if (rc != 0)
* where starts the last session ?) */
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = 0xc7;
- cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
+ cmd[1] |= 0x03;
rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
if (rc == -EINVAL) {
printk(KERN_INFO "sr%d: Hmm, seems the drive "
case VENDOR_WRITER:
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_TOC;
- cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
cmd[8] = 0x04;
cmd[9] = 0x40;
rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
break;
}
cmd[0] = READ_TOC; /* Read TOC */
- cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
+ (scsi_CDs[minor].device->lun << 5) : 0;
cmd[6] = rc & 0x7f; /* number of last session */
cmd[8] = 0x0c;
cmd[9] = 0x40;
}
}
- cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
+ if (SRpnt->sr_device->scsi_level <= SCSI_2)
+ cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
init_MUTEX_LOCKED(&STp->sem);
SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
(STp->buffer)->use_sg : 0;
Scsi_Tape *tpnt;
ST_mode *STm;
ST_partstat *STps;
- int i, mode, target_nbr;
+ int i, mode, target_nbr, dev_num;
unsigned long flags = 0;
char *stp;
}
memset(tpnt, 0, sizeof(Scsi_Tape));
scsi_tapes[i] = tpnt;
+ dev_num = i;
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
char name[8];
st_template.nr_dev++;
write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ printk(KERN_WARNING
+ "Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
+ dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
/* See if we need to allocate more static buffers */
target_nbr = st_template.nr_dev;
{
if (SDp->type != TYPE_TAPE || st_incompatible(SDp))
return 0;
-
- printk(KERN_WARNING
- "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
- st_template.dev_noticed++,
- SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
-
+ st_template.dev_noticed++;
return 1;
}
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3a-20010304"
+#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3c-20010512"
#define SCSI_NCR_DEBUG_FLAGS (0)
#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
#define pci_enable_device(pdev) (0)
#endif
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
+#define scsi_set_pci_device(inst, pdev) (0)
+#endif
/*==========================================================
**
SIR_MSG_RECEIVED,
}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
- SCR_LOAD_REL (scratcha1, 4), /* DUMMY READ */
+ SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
0,
SCR_INT,
SIR_MSG_WEIRD,
**
**----------------------------------------------------
*/
-#if 0 /* This stuff was only usefull for linux-1.2.13 */
+#if 0 /* This stuff was only useful for linux-1.2.13 */
if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
lp->numtags = tp->usrtags;
ncr_setup_tags (np, cp->target, cp->lun);
u_char istat;
int i;
+ if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN))
+ goto do_chip_reset;
+
OUTB (nc_istat, CABRT);
- for (i = 1000000 ; i ; --i) {
+ for (i = 100000 ; i ; --i) {
istat = INB (nc_istat);
if (istat & SIP) {
INW (nc_sist);
- continue;
}
- if (istat & DIP) {
- OUTB (nc_istat, 0);
- INB (nc_dstat);
- break;
+ else if (istat & DIP) {
+ if (INB (nc_dstat) & ABRT);
+ break;
}
+ UDELAY(5);
}
+ OUTB (nc_istat, 0);
if (!i)
- printk("%s: unable to abort current chip operation.\n",
- ncr_name(np));
+ printk("%s: unable to abort current chip operation, "
+ "ISTAT=0x%02x.\n", ncr_name(np), istat);
+do_chip_reset:
ncr_chip_reset(np);
}
/*
** On standard INQUIRY response (EVPD and CmDt
** not set), setup logical unit according to
- ** announced capabilities (we need the 1rst 7 bytes).
+ ** announced capabilities (we need the 1rst 8 bytes).
*/
if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
- cmd->cmnd[4] >= 7 && !cmd->use_sg) {
+ cmd->request_bufflen - cp->resid > 7 && !cmd->use_sg) {
sync_scsi_data(np, cmd); /* SYNC the data */
ncr_setup_lcb (np, cp->target, cp->lun,
(char *) cmd->request_buffer);
*/
fak = (kpc - 1) / div_10M[div] + 1;
-#if 0 /* This optimization does not seem very usefull */
+#if 0 /* This optimization does not seem very useful */
per = (fak * div_10M[div]) / clk;
** scntl3: (see the manual)
**
** current script command:
-** dsp: script adress (relative to start of script).
+** dsp: script address (relative to start of script).
** dbc: first word of script command.
**
** First 24 register of the chip:
#ifdef SYM_DEBUG_PM_WITH_WSR
PRINT_ADDR(cp);
- printf ("MA interrupt with WSR set - "
+ printk ("MA interrupt with WSR set - "
"pm->sg.addr=%x - pm->sg.size=%d\n",
pm->sg.addr, pm->sg.size);
#endif
if (i >= MAX_START*2)
i = 0;
}
- assert(k != -1);
- if (k != 1) {
+ /*
+ ** If job removed, repair the start queue.
+ */
+ if (k != -1) {
np->squeue[k] = np->squeue[i]; /* Idle task */
np->squeueput = k; /* Start queue pointer */
- cp->host_status = HS_ABORTED;
- cp->scsi_status = S_ILLEGAL;
- ncr_complete(np, cp);
}
+ cp->host_status = HS_ABORTED;
+ cp->scsi_status = S_ILLEGAL;
+ ncr_complete(np, cp);
}
break;
/*
** Was Sie schon immer ueber transfermode negotiation wissen wollten ...
**
** We try to negotiate sync and wide transfer only after
-** a successfull inquire command. We look at byte 7 of the
+** a successful inquire command. We look at byte 7 of the
** inquire data to determine the capabilities of the target.
**
** When we try to negotiate, we append the negotiation message
/*==========================================================
**
**
-** Aquire a control block
+** Acquire a control block
**
**
**==========================================================
static int __init ncr_snooptest (struct ncb* np)
{
u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
+ u_char dstat;
int i, err=0;
#ifndef SCSI_NCR_IOMAPPED
if (np->reg) {
if (err) return (err);
}
#endif
+restart_test:
+ /*
+ ** Enable Master Parity Checking as we intend
+ ** to enable it for normal operations.
+ */
+ OUTB (nc_ctest4, (np->rv_ctest4 & MPEE));
/*
** init
*/
for (i=0; i<NCR_SNOOP_TIMEOUT; i++)
if (INB(nc_istat) & (INTF|SIP|DIP))
break;
+ if (i>=NCR_SNOOP_TIMEOUT) {
+ printk ("CACHE TEST FAILED: timeout.\n");
+ return (0x20);
+ };
+ /*
+ ** Check for fatal DMA errors.
+ */
+ dstat = INB (nc_dstat);
+#if 1 /* Band aiding for broken hardwares that fail PCI parity */
+ if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) {
+ printk ("%s: PCI DATA PARITY ERROR DETECTED - "
+ "DISABLING MASTER DATA PARITY CHECKING.\n",
+ ncr_name(np));
+ np->rv_ctest4 &= ~MPEE;
+ goto restart_test;
+ }
+#endif
+ if (dstat & (MDPE|BF|IID)) {
+ printk ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat);
+ return (0x80);
+ }
/*
** Save termination position.
*/
host_rd = scr_to_cpu(np->ncr_cache);
ncr_rd = INL (nc_scratcha);
ncr_bk = INL (nc_temp);
-
- /*
- ** check for timeout
- */
- if (i>=NCR_SNOOP_TIMEOUT) {
- printk ("CACHE TEST FAILED: timeout.\n");
- return (0x20);
- };
/*
** Check termination position.
*/
/* save current state of GPCNTL and GPREG */
old_gpreg = INB (nc_gpreg);
old_gpcntl = INB (nc_gpcntl);
- gpcntl = old_gpcntl & 0xfc;
+ gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB (nc_gpreg, old_gpreg);
#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
#define pci_enable_device(pdev) (0)
#endif
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
+#define scsi_set_pci_device(inst, pdev) (0)
+#endif
/*==========================================================
**
/* save current state of GPCNTL and GPREG */
old_gpreg = INB (nc_gpreg);
old_gpcntl = INB (nc_gpcntl);
- gpcntl = old_gpcntl & 0xfc;
+ gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB (nc_gpreg, old_gpreg);
#endif
/*
- * Use normal IO if configured. Forced for alpha and powerpc.
- * Powerpc fails copying to on-chip RAM using memcpy_toio().
+ * Use normal IO if configured. Forced for alpha.
*/
#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
#define SCSI_NCR_IOMAPPED
#elif defined(__alpha__)
#define SCSI_NCR_IOMAPPED
#elif defined(__powerpc__)
+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,3)
#define SCSI_NCR_IOMAPPED
#define SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+#endif
#elif defined(__sparc__)
#undef SCSI_NCR_IOMAPPED
#endif
#define FE_PFEN (1<<12) /* Prefetch enable */
#define FE_LDSTR (1<<13) /* Load/Store supported */
#define FE_RAM (1<<14) /* On chip RAM present */
-#define FE_VARCLK (1<<15) /* SCSI lock may vary */
+#define FE_VARCLK (1<<15) /* SCSI clock may vary */
#define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */
#define FE_64BIT (1<<17) /* Have a 64-bit PCI interface */
#define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */
#define FE_ULTRA3 (1<<22) /* Ultra-3 80Mtrans/sec */
#define FE_66MHZ (1<<23) /* 66MHz PCI Support */
#define FE_DAC (1<<24) /* Support DAC cycles (64 bit addressing) */
+#define FE_ISTAT1 (1<<25) /* Have ISTAT1, MBOX0, MBOX1 registers */
#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
#define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
, \
{PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, \
FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
- FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC} \
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ISTAT1} \
, \
{PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a", 6, 31, 7, \
FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
FE_RAM|FE_IO256} \
, \
{PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010-33", 6, 62, 7, \
- FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1| \
FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3} \
, \
{PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66", 6, 62, 7, \
- FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1| \
FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3| \
FE_66MHZ} \
}
#define SIP 0x02 /* sta: scsi-interrupt */
#define DIP 0x01 /* sta: host/script interrupt */
-/*15*/ u_char nc_istat1; /* 896 only */
-/*16*/ u_char nc_mbox0; /* 896 only */
-/*17*/ u_char nc_mbox1; /* 896 only */
+/*15*/ u_char nc_istat1; /* 896 and later cores only */
+ #define FLSH 0x04 /* sta: chip is flushing */
+ #define SRUN 0x02 /* sta: scripts are running */
+ #define SIRQD 0x01 /* r/w: disable INT pin */
+
+/*16*/ u_char nc_mbox0; /* 896 and later cores only */
+/*17*/ u_char nc_mbox1; /* 896 and later cores only */
/*18*/ u_char nc_ctest0;
/*19*/ u_char nc_ctest1;
}
}
scr_writew(c, d);
- console_conditional_schedule();
s++;
d++;
} while (s < le);
if (s > start)
p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x);
- console_conditional_schedule();
if (offset > 0)
line++;
else {
* We should make sure we don't hold the superblock lock over
* block allocations, but for now:
*/
- if (!(gfp_mask & __GFP_IO))
+ if (!(gfp_mask & __GFP_FS))
return;
if (priority)
* want to recurse into the FS that called us
* in clear_inode() and friends..
*/
- if (!(gfp_mask & __GFP_IO))
+ if (!(gfp_mask & __GFP_FS))
return;
if (priority)
*/
struct pci_dev;
struct pci_board {
- unsigned short vendor;
- unsigned short device;
- unsigned short subvendor;
- unsigned short subdevice;
int flags;
int num_ports;
int base_baud;
trap_init();
init_IRQ();
sched_init();
- time_init();
softirq_init();
+ time_init();
/*
* HACK ALERT! This is early. We're enabling the console before
* loads, flush out the dirty pages before we have to wait on
* IO.
*/
- if ((CAN_DO_IO || CAN_DO_FS) && !launder_loop && free_shortage()) {
+ if (CAN_DO_IO && !launder_loop && free_shortage()) {
launder_loop = 1;
/* If we cleaned pages, never do synchronous IO. */
if (cleaned_pages)