/* time AHA spends on the AT-bus during data transfer */ staticint bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */
module_param_array(bus_on, int, NULL, 0);
MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])");
/* time AHA spends off the bus (not to monopolize it) during data transfer */ staticint bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */
module_param_array(bus_off, int, NULL, 0);
MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])");
#define BIOS_TRANSLATION_6432 1 /* Default case these days */ #define BIOS_TRANSLATION_25563 2 /* Big disk case */
struct aha1542_hostdata { /* This will effectively start both of them at the first mailbox */ int bios_translation; /* Mapping bios uses - for compatibility */ int aha1542_last_mbi_used; int aha1542_last_mbo_used; struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES]; struct mailbox *mb;
dma_addr_t mb_handle; struct ccb *ccb;
dma_addr_t ccb_handle;
};
staticint aha1542_out(unsignedint base, u8 *buf, int len)
{ while (len--) { if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) return 1;
outb(*buf++, DATA(base));
} if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0)) return 1;
return 0;
}
/* * Only used at boot time, so we do not need to worry about latency as much * here
*/
staticint aha1542_in(unsignedint base, u8 *buf, int len, int timeout)
{ while (len--) { if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) return 1;
*buf++ = inb(DATA(base));
} return 0;
}
staticint makecode(unsigned hosterr, unsigned scsierr)
{ switch (hosterr) { case 0x0: case 0xa: /* Linked command complete without error and linked normally */ case 0xb: /* Linked command complete without error, interrupt generated */
hosterr = 0; break;
case 0x11: /* Selection time out-The initiator selection or target * reselection was not complete within the SCSI Time out period
*/
hosterr = DID_TIME_OUT; break;
case 0x12: /* Data overrun/underrun-The target attempted to transfer more data * than was allocated by the Data Length field or the sum of the * Scatter / Gather Data Length fields.
*/
case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was * invalid. This usually indicates a software failure.
*/
case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. * This usually indicates a software failure.
*/
case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set * of linked CCB's does not specify the same logical unit number as * the first.
*/ case 0x18: /* Invalid Target Direction received from Host-The direction of a * Target Mode CCB was invalid.
*/
case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was * received to service data transfer between the same target LUN * and initiator SCSI ID in the same direction.
*/
case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero * length segment or invalid segment list boundaries was received. * A CCB parameter was invalid.
*/ #ifdef DEBUG
printk("Aha1542: %x %x\n", hosterr, scsierr); #endif
hosterr = DID_ERROR; /* Couldn't find any better */ break;
case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus * phase sequence was requested by the target. The host adapter * will generate a SCSI Reset Condition, notifying the host with * a SCRD interrupt
*/
hosterr = DID_RESET; break; default:
printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr); break;
} return scsierr | (hosterr << 16);
}
staticint aha1542_test_port(struct Scsi_Host *sh)
{ int i;
/* Quick and dirty test for presence of the card. */ if (inb(STATUS(sh->io_port)) == 0xff) return 0;
/* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
/* In case some other card was probing here, reset interrupts */
aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
mdelay(20); /* Wait a little bit for things to settle down. */
/* Expect INIT and IDLE, any of the others are bad */ if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) return 0;
/* Shouldn't have generated any interrupts during reset */ if (inb(INTRFLAGS(sh->io_port)) & INTRMASK) return 0;
/* * Perform a host adapter inquiry instead so we do not need to set * up the mailboxes ahead of time
*/
aha1542_outb(sh->io_port, CMD_INQUIRY);
for (i = 0; i < 4; i++) { if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0)) return 0;
(void)inb(DATA(sh->io_port));
}
/* Reading port should reset DF */ if (inb(STATUS(sh->io_port)) & DF) return 0;
/* When HACC, command is completed, and we're though testing */ if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0)) return 0;
#ifdef DEBUG
{
flag = inb(INTRFLAGS(sh->io_port));
shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: "); if (!(flag & ANYINTR))
printk("no interrupt?"); if (flag & MBIF)
printk("MBIF "); if (flag & MBOA)
printk("MBOF "); if (flag & HACC)
printk("HACC "); if (flag & SCRD)
printk("SCRD ");
printk("status %02x\n", inb(STATUS(sh->io_port)));
} #endif
number_serviced = 0;
spin_lock_irqsave(sh->host_lock, flags); while (1) {
flag = inb(INTRFLAGS(sh->io_port));
/* * Check for unusual interrupts. If any of these happen, we should * probably do something special, but for now just printing a message * is sufficient. A SCSI reset detected is something that we really * need to deal with in some way.
*/ if (flag & ~MBIF) { if (flag & MBOA)
printk("MBOF "); if (flag & HACC)
printk("HACC "); if (flag & SCRD)
printk("SCRD ");
}
aha1542_intr_reset(sh->io_port);
mbi = aha1542->aha1542_last_mbi_used + 1; if (mbi >= 2 * AHA1542_MAILBOXES)
mbi = AHA1542_MAILBOXES;
do { if (mb[mbi].status != 0) break;
mbi++; if (mbi >= 2 * AHA1542_MAILBOXES)
mbi = AHA1542_MAILBOXES;
} while (mbi != aha1542->aha1542_last_mbi_used);
if (mb[mbi].status == 0) {
spin_unlock_irqrestore(sh->host_lock, flags); /* Hmm, no mail. Must have read it the last time around */ if (!number_serviced)
shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n"); return IRQ_HANDLED;
}
if (!tmp_cmd) {
spin_unlock_irqrestore(sh->host_lock, flags);
shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n");
shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat,
ccb[mbo].hastat, ccb[mbo].idlun, mbo); return IRQ_HANDLED;
}
aha1542_free_cmd(tmp_cmd); /* * Fetch the sense data, and tuck it away, in the required slot. The * Adaptec automatically fetches it, and there is no guarantee that * we will still have it in the cdb when we come back
*/ if (ccb[mbo].tarstat == 2)
memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
SCSI_SENSE_BUFFERSIZE);
/* is there mail :-) */
/* more error checking left out here */ if (mbistatus != 1) /* This is surely wrong, but I don't know what's right */
errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); else
errstatus = 0;
#ifdef DEBUG if (errstatus)
shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus,
ccb[mbo].hastat, ccb[mbo].tarstat); if (ccb[mbo].tarstat == 2)
print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12); if (errstatus)
printk("aha1542_intr_handle: returning %6x\n", errstatus); #endif
tmp_cmd->result = errstatus;
aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as * far as queuecommand is concerned
*/
scsi_done(tmp_cmd);
number_serviced++;
}
}
if (*cmd->cmnd == REQUEST_SENSE) { /* Don't do the command - we have the sense data already */
cmd->result = 0;
scsi_done(cmd); return 0;
} #ifdef DEBUG
{ int i = -1; if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
i = xscsi2int(cmd->cmnd + 2); elseif (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
i = scsi2int(cmd->cmnd + 2);
shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d",
target, *cmd->cmnd, i, bufflen);
print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
} #endif
/* Query the board to find out if it is a 1542 or a 1740, or whatever. */ staticint aha1542_query(struct Scsi_Host *sh)
{ struct aha1542_hostdata *aha1542 = shost_priv(sh);
u8 inquiry_result[4]; int i;
i = inb(STATUS(sh->io_port)); if (i & DF) {
i = inb(DATA(sh->io_port));
}
aha1542_outb(sh->io_port, CMD_INQUIRY);
aha1542_in(sh->io_port, inquiry_result, 4, 0); if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
shost_printk(KERN_ERR, sh, "error querying card type\n");
aha1542_intr_reset(sh->io_port);
aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */
/* * For an AHA1740 series board, we ignore the board since there is a * hardware bug which can lead to wrong blocks being returned if the board * is operating in the 1542 emulation mode. Since there is an extended mode * driver, we simply ignore the board and let the 1740 driver pick it up.
*/
if (inquiry_result[0] == 0x43) {
shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n"); return 1;
}
/* * Always call this - boards that do not support extended bios translation * will ignore the command, and we will set the proper default
*/
aha1542->bios_translation = aha1542_mbenable(sh);
return 0;
}
static u8 dma_speed_hw(int dma_speed)
{ switch (dma_speed) { case 5: return 0x00; case 6: return 0x04; case 7: return 0x01; case 8: return 0x02; case 10: return 0x03;
}
return 0xff; /* invalid */
}
/* Set the Bus on/off-times as not to ruin floppy performance */ staticvoid aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed)
{ if (bus_on > 0) {
u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
aha1542_intr_reset(sh->io_port); if (aha1542_out(sh->io_port, oncmd, 2)) goto fail;
}
/* * Now tell the 1542 to flush all pending commands for this * target
*/
aha1542_outb(sh->io_port, CMD_START_SCSI);
spin_unlock_irqrestore(sh->host_lock, flags);
scmd_printk(KERN_WARNING, cmd, "Trying device reset for target\n");
spin_lock_irqsave(sh->host_lock, flags); /* * This does a scsi reset for all devices on the bus. * In principle, we could also reset the 1542 - should * we do this? Try this first, and we can add that later * if it turns out to be useful.
*/
outb(reset_cmd, CONTROL(cmd->device->host->io_port));
/* * We need to do this too before the 1542 can interact with * us again after host reset.
*/ if (reset_cmd & HRST)
setup_mailboxes(cmd->device->host);
/* * Now try to pick up the pieces. For all pending commands, * free any internal data structures, and basically clear things * out. We do not try and restart any commands or anything - * the strategy handler takes care of that crap.
*/
shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no);
for (i = 0; i < AHA1542_MAILBOXES; i++) { if (aha1542->int_cmds[i] != NULL) { struct scsi_cmnd *tmp_cmd;
tmp_cmd = aha1542->int_cmds[i];
if (tmp_cmd->device->soft_reset) { /* * If this device implements the soft reset option, * then it is still holding onto the command, and * may yet complete it. In this case, we don't * flush the data.
*/ continue;
}
aha1542_free_cmd(tmp_cmd);
aha1542->int_cmds[i] = NULL;
aha1542->mb[i].status = 0;
}
}
staticint __init aha1542_init(void)
{ int ret = 0;
#ifdef CONFIG_PNP if (isapnp) {
ret = pnp_register_driver(&aha1542_pnp_driver); if (!ret)
pnp_registered = 1;
} #endif
ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS); if (!ret)
isa_registered = 1;
#ifdef CONFIG_PNP if (pnp_registered)
ret = 0; #endif if (isa_registered)
ret = 0;
return ret;
}
staticvoid __exit aha1542_exit(void)
{ #ifdef CONFIG_PNP if (pnp_registered)
pnp_unregister_driver(&aha1542_pnp_driver); #endif if (isa_registered)
isa_unregister_driver(&aha1542_isa_driver);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.