示例#1
0
/**
 * qla2x00_isp_cmd() - Modify the request ring pointer.
 * @ha: HA context
 *
 * Note: The caller must hold the hardware lock before calling this routine.
 */
void
qla2x00_isp_cmd(scsi_qla_host_t *ha)
{
    device_reg_t __iomem *reg = ha->iobase;

    DEBUG5(printk("%s(): IOCB data:\n", __func__));
    DEBUG5(qla2x00_dump_buffer(
               (uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE));

    /* Adjust ring index. */
    ha->req_ring_index++;
    if (ha->req_ring_index == ha->request_q_length) {
        ha->req_ring_index = 0;
        ha->request_ring_ptr = ha->request_ring;
    } else
        ha->request_ring_ptr++;

    /* Set chip new ring index. */
    if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
        WRT_REG_DWORD(&reg->isp24.req_q_in, ha->req_ring_index);
        RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
    } else {
        WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp), ha->req_ring_index);
        RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
    }

}
示例#2
0
static irqreturn_t
qla24xx_msix_rsp_q(int irq, void *dev_id)
{
	scsi_qla_host_t	*ha;
	struct device_reg_24xx __iomem *reg;
	unsigned long flags;

	ha = dev_id;
	reg = &ha->iobase->isp24;

	spin_lock_irqsave(&ha->hardware_lock, flags);

	qla24xx_process_response_queue(ha);

	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
	RD_REG_DWORD_RELAXED(&reg->hccr);

	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return IRQ_HANDLED;
}
示例#3
0
/**
 * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
 * @irq:
 * @dev_id: SCSI driver HA context
 * @regs:
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */
irqreturn_t
qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
	scsi_qla_host_t	*ha;
	struct device_reg_24xx __iomem *reg;
	int		status;
	unsigned long	flags;
	unsigned long	iter;
	uint32_t	stat;
	uint32_t	hccr;
	uint16_t	mb[4];

	ha = (scsi_qla_host_t *) dev_id;
	if (!ha) {
		printk(KERN_INFO
		    "%s(): NULL host pointer\n", __func__);
		return IRQ_NONE;
	}

	reg = &ha->iobase->isp24;
	status = 0;

	spin_lock_irqsave(&ha->hardware_lock, flags);
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
			hccr = RD_REG_DWORD(&reg->hccr);

			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
			    "Dumping firmware!\n", hccr);
			qla24xx_fw_dump(ha, 1);

			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
			qla24xx_mbx_completion(ha, MSW(stat));
			status |= MBX_INTERRUPT;

			break;
		case 0x12:
			mb[0] = MSW(stat);
			mb[1] = RD_REG_WORD(&reg->mailbox1);
			mb[2] = RD_REG_WORD(&reg->mailbox2);
			mb[3] = RD_REG_WORD(&reg->mailbox3);
			qla2x00_async_event(ha, mb);
			break;
		case 0x13:
			qla24xx_process_response_queue(ha);
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
			    ha->host_no, stat & 0xff));
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
	}
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		spin_lock_irqsave(&ha->mbx_reg_lock, flags);

		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
		up(&ha->mbx_intr_sem);

		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
	}

	return IRQ_HANDLED;
}
示例#4
0
/**
 * qla24xx_start_scsi() - Send a SCSI command to the ISP
 * @sp: command to send to the ISP
 *
 * Returns non-zero if a failure occured, else zero.
 */
int
qla24xx_start_scsi(srb_t *sp)
{
    int		ret;
    unsigned long   flags;
    scsi_qla_host_t	*ha;
    struct scsi_cmnd *cmd;
    uint32_t	*clr_ptr;
    uint32_t        index;
    uint32_t	handle;
    struct cmd_type_7 *cmd_pkt;
    struct scatterlist *sg;
    uint16_t	cnt;
    uint16_t	req_cnt;
    uint16_t	tot_dsds;
    struct device_reg_24xx __iomem *reg;

    /* Setup device pointers. */
    ret = 0;
    ha = sp->ha;
    reg = &ha->iobase->isp24;
    cmd = sp->cmd;
    /* So we know we haven't pci_map'ed anything yet */
    tot_dsds = 0;

    /* Send marker if required */
    if (ha->marker_needed != 0) {
        if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
            return QLA_FUNCTION_FAILED;
        }
        ha->marker_needed = 0;
    }

    /* Acquire ring specific lock */
    spin_lock_irqsave(&ha->hardware_lock, flags);

    /* Check for room in outstanding command list. */
    handle = ha->current_outstanding_cmd;
    for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
        handle++;
        if (handle == MAX_OUTSTANDING_COMMANDS)
            handle = 1;
        if (ha->outstanding_cmds[handle] == 0)
            break;
    }
    if (index == MAX_OUTSTANDING_COMMANDS)
        goto queuing_error;

    /* Map the sg table so we have an accurate count of sg entries needed */
    if (cmd->use_sg) {
        sg = (struct scatterlist *) cmd->request_buffer;
        tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
                              cmd->sc_data_direction);
        if (tot_dsds == 0)
            goto queuing_error;
    } else if (cmd->request_bufflen) {
        dma_addr_t      req_dma;

        req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
                                 cmd->request_bufflen, cmd->sc_data_direction);
        if (dma_mapping_error(req_dma))
            goto queuing_error;

        sp->dma_handle = req_dma;
        tot_dsds = 1;
    }

    req_cnt = qla24xx_calc_iocbs(tot_dsds);
    if (ha->req_q_cnt < (req_cnt + 2)) {
        cnt = (uint16_t)RD_REG_DWORD_RELAXED(&reg->req_q_out);
        if (ha->req_ring_index < cnt)
            ha->req_q_cnt = cnt - ha->req_ring_index;
        else
            ha->req_q_cnt = ha->request_q_length -
                            (ha->req_ring_index - cnt);
    }
    if (ha->req_q_cnt < (req_cnt + 2))
        goto queuing_error;

    /* Build command packet. */
    ha->current_outstanding_cmd = handle;
    ha->outstanding_cmds[handle] = sp;
    sp->ha = ha;
    sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
    ha->req_q_cnt -= req_cnt;

    cmd_pkt = (struct cmd_type_7 *)ha->request_ring_ptr;
    cmd_pkt->handle = handle;

    /* Zero out remaining portion of packet. */
    /*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
    clr_ptr = (uint32_t *)cmd_pkt + 2;
    memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
    cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);

    /* Set NPORT-ID and LUN number*/
    cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
    cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
    cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
    cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;

    int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
    host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));

    /* Load SCSI command packet. */
    memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
    host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));

    cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);

    /* Build IOCB segments */
    qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds);

    /* Set total data segment count. */
    cmd_pkt->entry_count = (uint8_t)req_cnt;
    wmb();

    /* Adjust ring index. */
    ha->req_ring_index++;
    if (ha->req_ring_index == ha->request_q_length) {
        ha->req_ring_index = 0;
        ha->request_ring_ptr = ha->request_ring;
    } else
        ha->request_ring_ptr++;

    sp->flags |= SRB_DMA_VALID;
    sp->state = SRB_ACTIVE_STATE;

    /* Set chip new ring index. */
    WRT_REG_DWORD(&reg->req_q_in, ha->req_ring_index);
    RD_REG_DWORD_RELAXED(&reg->req_q_in);		/* PCI Posting. */

    /* Manage unprocessed RIO/ZIO commands in response queue. */
    if (ha->flags.process_response_queue &&
            ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
        qla24xx_process_response_queue(ha);

    spin_unlock_irqrestore(&ha->hardware_lock, flags);
    return QLA_SUCCESS;

queuing_error:
    if (cmd->use_sg && tot_dsds) {
        sg = (struct scatterlist *) cmd->request_buffer;
        pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
                     cmd->sc_data_direction);
    } else if (tot_dsds) {
        pci_unmap_single(ha->pdev, sp->dma_handle,
                         cmd->request_bufflen, cmd->sc_data_direction);
    }
    spin_unlock_irqrestore(&ha->hardware_lock, flags);

    return QLA_FUNCTION_FAILED;
}