static irqreturn_t aha1542_interrupt(int irq, void *dev_id) { struct Scsi_Host *sh = dev_id; struct aha1542_hostdata *aha1542 = shost_priv(sh); void (*my_done)(struct scsi_cmnd *) = NULL; int errstatus, mbi, mbo, mbistatus; int number_serviced; unsigned long flags; struct scsi_cmnd *tmp_cmd; int flag; struct mailbox *mb = aha1542->mb; struct ccb *ccb = aha1542->ccb; #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; }; mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb); mbistatus = mb[mbi].status; mb[mbi].status = 0; aha1542->aha1542_last_mbi_used = mbi; #ifdef DEBUG if (ccb[mbo].tarstat | ccb[mbo].hastat) shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n", ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); #endif if (mbistatus == 3) continue; /* Aborted command not found */ #ifdef DEBUG shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi); #endif tmp_cmd = aha1542->int_cmds[mbo]; if (!tmp_cmd || !tmp_cmd->scsi_done) { 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; } my_done = tmp_cmd->scsi_done; kfree(tmp_cmd->host_scribble); tmp_cmd->host_scribble = NULL; /* 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 */ my_done(tmp_cmd); number_serviced++; }; }
static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct aha1542_hostdata *aha1542 = shost_priv(sh); u8 direction; u8 target = cmd->device->id; u8 lun = cmd->device->lun; unsigned long flags; int bufflen = scsi_bufflen(cmd); int mbo, sg_count; struct mailbox *mb = aha1542->mb; struct ccb *ccb = aha1542->ccb; struct chain *cptr; if (*cmd->cmnd == REQUEST_SENSE) { /* Don't do the command - we have the sense data already */ cmd->result = 0; cmd->scsi_done(cmd); return 0; } #ifdef DEBUG { int i = -1; if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10) i = xscsi2int(cmd->cmnd + 2); else if (*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 if (bufflen) { /* allocate memory before taking host_lock */ sg_count = scsi_sg_count(cmd); cptr = kmalloc(sizeof(*cptr) * sg_count, GFP_KERNEL | GFP_DMA); if (!cptr) return SCSI_MLQUEUE_HOST_BUSY; } else { sg_count = 0; cptr = NULL; } /* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them */ spin_lock_irqsave(sh->host_lock, flags); mbo = aha1542->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; do { if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) break; mbo++; if (mbo >= AHA1542_MAILBOXES) mbo = 0; } while (mbo != aha1542->aha1542_last_mbo_used); if (mb[mbo].status || aha1542->int_cmds[mbo]) panic("Unable to find empty mailbox for aha1542.\n"); aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from screwing with this cdb. */ aha1542->aha1542_last_mbo_used = mbo; #ifdef DEBUG shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done); #endif any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */ memset(&ccb[mbo], 0, sizeof(struct ccb)); ccb[mbo].cdblen = cmd->cmd_len; direction = 0; if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6) direction = 8; else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6) direction = 16; memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen); if (bufflen) { struct scatterlist *sg; int i; ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ cmd->host_scribble = (void *)cptr; scsi_for_each_sg(cmd, sg, sg_count, i) { any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset); any2scsi(cptr[i].datalen, sg->length); }; any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr)); #ifdef DEBUG shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr); print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18); #endif } else {
static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); struct aha1542_hostdata *aha1542 = shost_priv(sh); u8 direction; u8 target = cmd->device->id; u8 lun = cmd->device->lun; unsigned long flags; int bufflen = scsi_bufflen(cmd); int mbo, sg_count; struct mailbox *mb = aha1542->mb; struct ccb *ccb = aha1542->ccb; if (*cmd->cmnd == REQUEST_SENSE) { /* Don't do the command - we have the sense data already */ cmd->result = 0; cmd->scsi_done(cmd); return 0; } #ifdef DEBUG { int i = -1; if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10) i = xscsi2int(cmd->cmnd + 2); else if (*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 sg_count = scsi_dma_map(cmd); if (sg_count) { size_t len = sg_count * sizeof(struct chain); acmd->chain = kmalloc(len, GFP_DMA); if (!acmd->chain) goto out_unmap; acmd->chain_handle = dma_map_single(sh->dma_dev, acmd->chain, len, DMA_TO_DEVICE); if (dma_mapping_error(sh->dma_dev, acmd->chain_handle)) goto out_free_chain; } /* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them */ spin_lock_irqsave(sh->host_lock, flags); mbo = aha1542->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; do { if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) break; mbo++; if (mbo >= AHA1542_MAILBOXES) mbo = 0; } while (mbo != aha1542->aha1542_last_mbo_used); if (mb[mbo].status || aha1542->int_cmds[mbo]) panic("Unable to find empty mailbox for aha1542.\n"); aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from screwing with this cdb. */ aha1542->aha1542_last_mbo_used = mbo; #ifdef DEBUG shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done); #endif /* This gets trashed for some reason */ any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); memset(&ccb[mbo], 0, sizeof(struct ccb)); ccb[mbo].cdblen = cmd->cmd_len; direction = 0; if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6) direction = 8; else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6) direction = 16; memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen); if (bufflen) { struct scatterlist *sg; int i; ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ scsi_for_each_sg(cmd, sg, sg_count, i) { any2scsi(acmd->chain[i].dataptr, sg_dma_address(sg)); any2scsi(acmd->chain[i].datalen, sg_dma_len(sg)); }; any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); any2scsi(ccb[mbo].dataptr, acmd->chain_handle); #ifdef DEBUG shost_printk(KERN_DEBUG, sh, "cptr %p: ", acmd->chain); print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, acmd->chain, 18); #endif } else {