Exemplo n.º 1
0
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++;
    };
}
Exemplo n.º 2
0
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 {
Exemplo n.º 3
0
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 {