Esempio n. 1
0
/**
 * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query.
 * @ha: HA context
 * @req_size: request size in bytes
 * @rsp_size: response size in bytes
 *
 * Returns a pointer to the @ha's ms_iocb.
 */
void *
qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
{
	struct qla_hw_data *ha = vha->hw;
	ms_iocb_entry_t *ms_pkt;

	ms_pkt = ha->ms_iocb;
	memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));

	ms_pkt->entry_type = MS_IOCB_TYPE;
	ms_pkt->entry_count = 1;
	SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER);
	ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
	ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
	ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
	ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
	ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
	ms_pkt->req_bytecount = cpu_to_le32(req_size);

	ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
	ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
	ms_pkt->dseg_req_length = ms_pkt->req_bytecount;

	ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
	ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
	ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;

	return (ms_pkt);
}
Esempio n. 2
0
/**
 * qla2x00_marker() - Send a marker IOCB to the firmware.
 * @ha: HA context
 * @loop_id: loop ID
 * @lun: LUN
 * @type: marker modifier
 *
 * Can be called from both normal and interrupt context.
 *
 * Returns non-zero if a failure occured, else zero.
 */
int
__qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
    uint8_t type)
{
	mrk_entry_t	*pkt;

	pkt = (mrk_entry_t *)qla2x00_req_pkt(ha);
	if (pkt == NULL) {
		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));

		return (QLA_FUNCTION_FAILED);
	}

	pkt->entry_type = MARKER_TYPE;
	pkt->modifier = type;

	if (type != MK_SYNC_ALL) {
		pkt->lun = cpu_to_le16(lun);
		SET_TARGET_ID(ha, pkt->target, loop_id);
	}

	/* Issue command to ISP */
	qla2x00_isp_cmd(ha);

	return (QLA_SUCCESS);
}
Esempio n. 3
0
/**
 * qla2x00_marker() - Send a marker IOCB to the firmware.
 * @ha: HA context
 * @loop_id: loop ID
 * @lun: LUN
 * @type: marker modifier
 *
 * Can be called from both normal and interrupt context.
 *
 * Returns non-zero if a failure occured, else zero.
 */
int
__qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
                 uint8_t type)
{
    mrk_entry_t *mrk;
    struct mrk_entry_24xx *mrk24;

    mrk24 = NULL;
    mrk = (mrk_entry_t *)qla2x00_req_pkt(ha);
    if (mrk == NULL) {
        DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
                        __func__, ha->host_no));

        return (QLA_FUNCTION_FAILED);
    }

    mrk->entry_type = MARKER_TYPE;
    mrk->modifier = type;
    if (type != MK_SYNC_ALL) {
        if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
            mrk24 = (struct mrk_entry_24xx *) mrk;
            mrk24->nport_handle = cpu_to_le16(loop_id);
            mrk24->lun[1] = LSB(lun);
            mrk24->lun[2] = MSB(lun);
        } else {
            SET_TARGET_ID(ha, mrk->target, loop_id);
            mrk->lun = cpu_to_le16(lun);
        }
    }
    wmb();

    qla2x00_isp_cmd(ha);

    return (QLA_SUCCESS);
}
Esempio n. 4
0
/**
 * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
 * @ha: HA context
 * @req_size: request size in bytes
 * @rsp_size: response size in bytes
 *
 * Returns a pointer to the @ha's ms_iocb.
 */
void *
qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
    uint32_t rsp_size)
{
	ms_iocb_entry_t *ms_pkt;

	ms_pkt = ha->ms_iocb;
	memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));

	ms_pkt->entry_type = MS_IOCB_TYPE;
	ms_pkt->entry_count = 1;
	SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id);
	ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
	ms_pkt->timeout = __constant_cpu_to_le16(59);
	ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
	ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
	ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
	ms_pkt->req_bytecount = cpu_to_le32(req_size);

	ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
	ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
	ms_pkt->dseg_req_length = ms_pkt->req_bytecount;

	ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
	ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
	ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;

	return ms_pkt;
}
Esempio n. 5
0
/**
 * qla2x00_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
qla2x00_start_scsi(srb_t *sp)
{
	int		ret;
	unsigned long   flags;
	scsi_qla_host_t	*ha;
	fc_lun_t	*fclun;
	struct scsi_cmnd *cmd;
	uint32_t	*clr_ptr;
	uint32_t        index;
	uint32_t	handle;
	uint16_t	cnt;
	cmd_entry_t	*cmd_pkt;
	uint32_t        timeout;
	struct scatterlist *sg;

	device_reg_t	*reg;

	/* Setup device pointers. */
	ret = 0;
	fclun = sp->lun_queue->fclun;
	ha = fclun->fcport->ha;
	cmd = sp->cmd;
	reg = ha->iobase;

	/* 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;
	}

	/* Calculate number of segments and entries required. */
	if (sp->req_cnt == 0) {
		sp->tot_dsds = 0;
		if (cmd->use_sg) {
			sg = (struct scatterlist *) cmd->request_buffer;
			sp->tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
			    cmd->sc_data_direction);
		} else if (cmd->request_bufflen) {
		    sp->tot_dsds++;
		}
		sp->req_cnt = (ha->calc_request_entries)(sp->tot_dsds);
	}

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

	if (ha->req_q_cnt < (sp->req_cnt + 2)) {
		/* Calculate number of free request entries */
		cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
		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 no room for request in request ring */
	if (ha->req_q_cnt < (sp->req_cnt + 2)) {
		DEBUG5(printk("scsi(%ld): in-ptr=%x req_q_cnt=%x "
		    "tot_dsds=%x.\n",
		    ha->host_no, ha->req_ring_index, ha->req_q_cnt,
		    sp->tot_dsds));

		goto queuing_error;
	}

	/* 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) {
			ha->current_outstanding_cmd = handle;
			break;
		}
	}
	if (index == MAX_OUTSTANDING_COMMANDS) {
		DEBUG5(printk("scsi(%ld): Unable to queue command -- NO ROOM "
		    "IN OUTSTANDING ARRAY (req_q_cnt=%x).\n",
		    ha->host_no, ha->req_q_cnt));
		goto queuing_error;
	}

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

	cmd_pkt = (cmd_entry_t *)ha->request_ring_ptr;
	cmd_pkt->handle = handle;
	/* Zero out remaining portion of packet. */
	clr_ptr = (uint32_t *)cmd_pkt + 2;
	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
	cmd_pkt->dseg_count = cpu_to_le16(sp->tot_dsds);

	/* Set target ID */
	SET_TARGET_ID(ha, cmd_pkt->target, fclun->fcport->loop_id);

	/* Set LUN number*/
	cmd_pkt->lun = cpu_to_le16(fclun->lun);

	/* Update tagged queuing modifier */
	cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
	if (cmd->device->tagged_supported) {
		switch (cmd->tag) {
		case HEAD_OF_QUEUE_TAG:
			cmd_pkt->control_flags =
			    __constant_cpu_to_le16(CF_HEAD_TAG);
			break;
		case ORDERED_QUEUE_TAG:
			cmd_pkt->control_flags =
			    __constant_cpu_to_le16(CF_ORDERED_TAG);
			break;
		}
	}

	/*
	 * Allocate at least 5 (+ QLA_CMD_TIMER_DELTA) seconds for RISC timeout.
	 */
	timeout = (uint32_t)(cmd->timeout_per_command / HZ);
	if (timeout > 65535)
		cmd_pkt->timeout = __constant_cpu_to_le16(0);
	else if (timeout > 25)
		cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout -
		    (5 + QLA_CMD_TIMER_DELTA));
	else
		cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout);

	/* Load SCSI command packet. */
	memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
	cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);

	/* Build IOCB segments */
	(ha->build_scsi_iocbs)(sp, cmd_pkt, sp->tot_dsds);

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

	/* 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++;

	ha->actthreads++;
	ha->total_ios++;
	sp->lun_queue->out_cnt++;
	sp->flags |= SRB_DMA_VALID;
	sp->state = SRB_ACTIVE_STATE;
	sp->u_start = jiffies;

	/* Set chip new ring index. */
	WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
	RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg));	/* PCI Posting. */

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

queuing_error:
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return (QLA_FUNCTION_FAILED);
}
Esempio n. 6
0
/**
 * qla2x00_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
qla2x00_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;
    cmd_entry_t	*cmd_pkt;
    struct scatterlist *sg;
    uint16_t	cnt;
    uint16_t	req_cnt;
    uint16_t	tot_dsds;
    struct device_reg_2xxx __iomem *reg;

    /* Setup device pointers. */
    ret = 0;
    ha = sp->ha;
    reg = &ha->iobase->isp;
    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;
    }

    /* Calculate the number of request entries needed. */
    req_cnt = ha->isp_ops.calc_req_entries(tot_dsds);
    if (ha->req_q_cnt < (req_cnt + 2)) {
        cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
        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 = (cmd_entry_t *)ha->request_ring_ptr;
    cmd_pkt->handle = handle;
    /* Zero out remaining portion of packet. */
    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 target ID and LUN number*/
    SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id);
    cmd_pkt->lun = cpu_to_le16(sp->cmd->device->lun);

    /* Update tagged queuing modifier */
    cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);

    /* Load SCSI command packet. */
    memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
    cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);

    /* Build IOCB segments */
    ha->isp_ops.build_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_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
    RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg));	/* PCI Posting. */

    /* Manage unprocessed RIO/ZIO commands in response queue. */
    if (ha->flags.process_response_queue &&
            ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
        qla2x00_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);
}