xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_iocb.c (revision 924b3d7a)
1e3976af5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2afaf5a2dSDavid Somayajulu /*
3afaf5a2dSDavid Somayajulu  * QLogic iSCSI HBA Driver
44a4f51e9SVikas Chaudhary  * Copyright (c)  2003-2013 QLogic Corporation
5afaf5a2dSDavid Somayajulu  */
6afaf5a2dSDavid Somayajulu 
7afaf5a2dSDavid Somayajulu #include "ql4_def.h"
8e08c182cSDavid C Somayajulu #include "ql4_glbl.h"
9e08c182cSDavid C Somayajulu #include "ql4_dbg.h"
10e08c182cSDavid C Somayajulu #include "ql4_inline.h"
11e08c182cSDavid C Somayajulu 
12afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h>
13afaf5a2dSDavid Somayajulu 
1416ed55f9SKaren Higgins static int
qla4xxx_space_in_req_ring(struct scsi_qla_host * ha,uint16_t req_cnt)1516ed55f9SKaren Higgins qla4xxx_space_in_req_ring(struct scsi_qla_host *ha, uint16_t req_cnt)
1616ed55f9SKaren Higgins {
1716ed55f9SKaren Higgins 	uint16_t cnt;
1816ed55f9SKaren Higgins 
1916ed55f9SKaren Higgins 	/* Calculate number of free request entries. */
2016ed55f9SKaren Higgins 	if ((req_cnt + 2) >= ha->req_q_count) {
21b173a132SVikas Chaudhary 		cnt = (uint16_t) ha->isp_ops->rd_shdw_req_q_out(ha);
2216ed55f9SKaren Higgins 		if (ha->request_in < cnt)
2316ed55f9SKaren Higgins 			ha->req_q_count = cnt - ha->request_in;
2416ed55f9SKaren Higgins 		else
2516ed55f9SKaren Higgins 			ha->req_q_count = REQUEST_QUEUE_DEPTH -
2616ed55f9SKaren Higgins 						(ha->request_in - cnt);
2716ed55f9SKaren Higgins 	}
2816ed55f9SKaren Higgins 
2916ed55f9SKaren Higgins 	/* Check if room for request in request ring. */
3016ed55f9SKaren Higgins 	if ((req_cnt + 2) < ha->req_q_count)
3116ed55f9SKaren Higgins 		return 1;
3216ed55f9SKaren Higgins 	else
3316ed55f9SKaren Higgins 		return 0;
3416ed55f9SKaren Higgins }
3516ed55f9SKaren Higgins 
qla4xxx_advance_req_ring_ptr(struct scsi_qla_host * ha)3616ed55f9SKaren Higgins static void qla4xxx_advance_req_ring_ptr(struct scsi_qla_host *ha)
3716ed55f9SKaren Higgins {
3816ed55f9SKaren Higgins 	/* Advance request queue pointer */
3916ed55f9SKaren Higgins 	if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
4016ed55f9SKaren Higgins 		ha->request_in = 0;
4116ed55f9SKaren Higgins 		ha->request_ptr = ha->request_ring;
4216ed55f9SKaren Higgins 	} else {
4316ed55f9SKaren Higgins 		ha->request_in++;
4416ed55f9SKaren Higgins 		ha->request_ptr++;
4516ed55f9SKaren Higgins 	}
4616ed55f9SKaren Higgins }
4716ed55f9SKaren Higgins 
48afaf5a2dSDavid Somayajulu /**
49afaf5a2dSDavid Somayajulu  * qla4xxx_get_req_pkt - returns a valid entry in request queue.
50afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
51afaf5a2dSDavid Somayajulu  * @queue_entry: Pointer to pointer to queue entry structure
52afaf5a2dSDavid Somayajulu  *
53afaf5a2dSDavid Somayajulu  * This routine performs the following tasks:
54afaf5a2dSDavid Somayajulu  *	- returns the current request_in pointer (if queue not full)
55afaf5a2dSDavid Somayajulu  *	- advances the request_in pointer
56afaf5a2dSDavid Somayajulu  *	- checks for queue full
57afaf5a2dSDavid Somayajulu  **/
qla4xxx_get_req_pkt(struct scsi_qla_host * ha,struct queue_entry ** queue_entry)5847975477SAdrian Bunk static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
59afaf5a2dSDavid Somayajulu 			       struct queue_entry **queue_entry)
60afaf5a2dSDavid Somayajulu {
6116ed55f9SKaren Higgins 	uint16_t req_cnt = 1;
62afaf5a2dSDavid Somayajulu 
6316ed55f9SKaren Higgins 	if (qla4xxx_space_in_req_ring(ha, req_cnt)) {
64afaf5a2dSDavid Somayajulu 		*queue_entry = ha->request_ptr;
65afaf5a2dSDavid Somayajulu 		memset(*queue_entry, 0, sizeof(**queue_entry));
6616ed55f9SKaren Higgins 
6716ed55f9SKaren Higgins 		qla4xxx_advance_req_ring_ptr(ha);
6816ed55f9SKaren Higgins 		ha->req_q_count -= req_cnt;
6916ed55f9SKaren Higgins 		return QLA_SUCCESS;
70afaf5a2dSDavid Somayajulu 	}
71afaf5a2dSDavid Somayajulu 
7216ed55f9SKaren Higgins 	return QLA_ERROR;
73afaf5a2dSDavid Somayajulu }
74afaf5a2dSDavid Somayajulu 
75afaf5a2dSDavid Somayajulu /**
76afaf5a2dSDavid Somayajulu  * qla4xxx_send_marker_iocb - issues marker iocb to HBA
77afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
78afaf5a2dSDavid Somayajulu  * @ddb_entry: Pointer to device database entry
79afaf5a2dSDavid Somayajulu  * @lun: SCSI LUN
8067b8b93aSLee Jones  * @mrkr_mod: marker identifier
81afaf5a2dSDavid Somayajulu  *
82afaf5a2dSDavid Somayajulu  * This routine issues a marker IOCB.
83afaf5a2dSDavid Somayajulu  **/
qla4xxx_send_marker_iocb(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,uint64_t lun,uint16_t mrkr_mod)849d562913SDavid C Somayajulu int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
859cb78c16SHannes Reinecke 	struct ddb_entry *ddb_entry, uint64_t lun, uint16_t mrkr_mod)
86afaf5a2dSDavid Somayajulu {
871c3f0b8eSMathieu Desnoyers 	struct qla4_marker_entry *marker_entry;
88afaf5a2dSDavid Somayajulu 	unsigned long flags = 0;
89afaf5a2dSDavid Somayajulu 	uint8_t status = QLA_SUCCESS;
90afaf5a2dSDavid Somayajulu 
91afaf5a2dSDavid Somayajulu 	/* Acquire hardware specific lock */
92afaf5a2dSDavid Somayajulu 	spin_lock_irqsave(&ha->hardware_lock, flags);
93afaf5a2dSDavid Somayajulu 
94afaf5a2dSDavid Somayajulu 	/* Get pointer to the queue entry for the marker */
95afaf5a2dSDavid Somayajulu 	if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) !=
96afaf5a2dSDavid Somayajulu 	    QLA_SUCCESS) {
97afaf5a2dSDavid Somayajulu 		status = QLA_ERROR;
98afaf5a2dSDavid Somayajulu 		goto exit_send_marker;
99afaf5a2dSDavid Somayajulu 	}
100afaf5a2dSDavid Somayajulu 
101afaf5a2dSDavid Somayajulu 	/* Put the marker in the request queue */
102afaf5a2dSDavid Somayajulu 	marker_entry->hdr.entryType = ET_MARKER;
103afaf5a2dSDavid Somayajulu 	marker_entry->hdr.entryCount = 1;
104afaf5a2dSDavid Somayajulu 	marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
1059d562913SDavid C Somayajulu 	marker_entry->modifier = cpu_to_le16(mrkr_mod);
106afaf5a2dSDavid Somayajulu 	int_to_scsilun(lun, &marker_entry->lun);
107afaf5a2dSDavid Somayajulu 	wmb();
108afaf5a2dSDavid Somayajulu 
109afaf5a2dSDavid Somayajulu 	/* Tell ISP it's got a new I/O request */
110f4f5df23SVikas Chaudhary 	ha->isp_ops->queue_iocb(ha);
111afaf5a2dSDavid Somayajulu 
112afaf5a2dSDavid Somayajulu exit_send_marker:
113afaf5a2dSDavid Somayajulu 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
114afaf5a2dSDavid Somayajulu 	return status;
115afaf5a2dSDavid Somayajulu }
116afaf5a2dSDavid Somayajulu 
11716ed55f9SKaren Higgins static struct continuation_t1_entry *
qla4xxx_alloc_cont_entry(struct scsi_qla_host * ha)11816ed55f9SKaren Higgins qla4xxx_alloc_cont_entry(struct scsi_qla_host *ha)
119afaf5a2dSDavid Somayajulu {
120afaf5a2dSDavid Somayajulu 	struct continuation_t1_entry *cont_entry;
121afaf5a2dSDavid Somayajulu 
122afaf5a2dSDavid Somayajulu 	cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
123afaf5a2dSDavid Somayajulu 
12416ed55f9SKaren Higgins 	qla4xxx_advance_req_ring_ptr(ha);
125afaf5a2dSDavid Somayajulu 
126afaf5a2dSDavid Somayajulu 	/* Load packet defaults */
127afaf5a2dSDavid Somayajulu 	cont_entry->hdr.entryType = ET_CONTINUE;
128afaf5a2dSDavid Somayajulu 	cont_entry->hdr.entryCount = 1;
129afaf5a2dSDavid Somayajulu 	cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in);
130afaf5a2dSDavid Somayajulu 
131afaf5a2dSDavid Somayajulu 	return cont_entry;
132afaf5a2dSDavid Somayajulu }
133afaf5a2dSDavid Somayajulu 
qla4xxx_calc_request_entries(uint16_t dsds)13447975477SAdrian Bunk static uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
135afaf5a2dSDavid Somayajulu {
136afaf5a2dSDavid Somayajulu 	uint16_t iocbs;
137afaf5a2dSDavid Somayajulu 
138afaf5a2dSDavid Somayajulu 	iocbs = 1;
139afaf5a2dSDavid Somayajulu 	if (dsds > COMMAND_SEG) {
140afaf5a2dSDavid Somayajulu 		iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG;
141afaf5a2dSDavid Somayajulu 		if ((dsds - COMMAND_SEG) % CONTINUE_SEG)
142afaf5a2dSDavid Somayajulu 			iocbs++;
143afaf5a2dSDavid Somayajulu 	}
144afaf5a2dSDavid Somayajulu 	return iocbs;
145afaf5a2dSDavid Somayajulu }
146afaf5a2dSDavid Somayajulu 
qla4xxx_build_scsi_iocbs(struct srb * srb,struct command_t3_entry * cmd_entry,uint16_t tot_dsds)14747975477SAdrian Bunk static void qla4xxx_build_scsi_iocbs(struct srb *srb,
148afaf5a2dSDavid Somayajulu 				     struct command_t3_entry *cmd_entry,
149afaf5a2dSDavid Somayajulu 				     uint16_t tot_dsds)
150afaf5a2dSDavid Somayajulu {
151afaf5a2dSDavid Somayajulu 	struct scsi_qla_host *ha;
152afaf5a2dSDavid Somayajulu 	uint16_t avail_dsds;
153afaf5a2dSDavid Somayajulu 	struct data_seg_a64 *cur_dsd;
154afaf5a2dSDavid Somayajulu 	struct scsi_cmnd *cmd;
1555f7186c8SFUJITA Tomonori 	struct scatterlist *sg;
1565f7186c8SFUJITA Tomonori 	int i;
157afaf5a2dSDavid Somayajulu 
158afaf5a2dSDavid Somayajulu 	cmd = srb->cmd;
159afaf5a2dSDavid Somayajulu 	ha = srb->ha;
160afaf5a2dSDavid Somayajulu 
1615f7186c8SFUJITA Tomonori 	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
162afaf5a2dSDavid Somayajulu 		/* No data being transferred */
16333529018SDwaipayan Ray 		cmd_entry->ttlByteCnt = cpu_to_le32(0);
164afaf5a2dSDavid Somayajulu 		return;
165afaf5a2dSDavid Somayajulu 	}
166afaf5a2dSDavid Somayajulu 
167afaf5a2dSDavid Somayajulu 	avail_dsds = COMMAND_SEG;
168afaf5a2dSDavid Somayajulu 	cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
169afaf5a2dSDavid Somayajulu 
1705f7186c8SFUJITA Tomonori 	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
171afaf5a2dSDavid Somayajulu 		dma_addr_t sle_dma;
172afaf5a2dSDavid Somayajulu 
173afaf5a2dSDavid Somayajulu 		/* Allocate additional continuation packets? */
174afaf5a2dSDavid Somayajulu 		if (avail_dsds == 0) {
175afaf5a2dSDavid Somayajulu 			struct continuation_t1_entry *cont_entry;
176afaf5a2dSDavid Somayajulu 
177afaf5a2dSDavid Somayajulu 			cont_entry = qla4xxx_alloc_cont_entry(ha);
178afaf5a2dSDavid Somayajulu 			cur_dsd =
179afaf5a2dSDavid Somayajulu 				(struct data_seg_a64 *)
180afaf5a2dSDavid Somayajulu 				&cont_entry->dataseg[0];
181afaf5a2dSDavid Somayajulu 			avail_dsds = CONTINUE_SEG;
182afaf5a2dSDavid Somayajulu 		}
183afaf5a2dSDavid Somayajulu 
1845f7186c8SFUJITA Tomonori 		sle_dma = sg_dma_address(sg);
185afaf5a2dSDavid Somayajulu 		cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
186afaf5a2dSDavid Somayajulu 		cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
1875f7186c8SFUJITA Tomonori 		cur_dsd->count = cpu_to_le32(sg_dma_len(sg));
188afaf5a2dSDavid Somayajulu 		avail_dsds--;
189afaf5a2dSDavid Somayajulu 
190afaf5a2dSDavid Somayajulu 		cur_dsd++;
191afaf5a2dSDavid Somayajulu 	}
192afaf5a2dSDavid Somayajulu }
193afaf5a2dSDavid Somayajulu 
qla4_83xx_queue_iocb(struct scsi_qla_host * ha)1946e7b4292SVikas Chaudhary void qla4_83xx_queue_iocb(struct scsi_qla_host *ha)
1956e7b4292SVikas Chaudhary {
1966e7b4292SVikas Chaudhary 	writel(ha->request_in, &ha->qla4_83xx_reg->req_q_in);
1976e7b4292SVikas Chaudhary 	readl(&ha->qla4_83xx_reg->req_q_in);
1986e7b4292SVikas Chaudhary }
1996e7b4292SVikas Chaudhary 
qla4_83xx_complete_iocb(struct scsi_qla_host * ha)2006e7b4292SVikas Chaudhary void qla4_83xx_complete_iocb(struct scsi_qla_host *ha)
2016e7b4292SVikas Chaudhary {
2026e7b4292SVikas Chaudhary 	writel(ha->response_out, &ha->qla4_83xx_reg->rsp_q_out);
2036e7b4292SVikas Chaudhary 	readl(&ha->qla4_83xx_reg->rsp_q_out);
2046e7b4292SVikas Chaudhary }
2056e7b4292SVikas Chaudhary 
206afaf5a2dSDavid Somayajulu /**
207f8086f4fSVikas Chaudhary  * qla4_82xx_queue_iocb - Tell ISP it's got new request(s)
208f4f5df23SVikas Chaudhary  * @ha: pointer to host adapter structure.
209f4f5df23SVikas Chaudhary  *
210f4f5df23SVikas Chaudhary  * This routine notifies the ISP that one or more new request
211f4f5df23SVikas Chaudhary  * queue entries have been placed on the request queue.
212f4f5df23SVikas Chaudhary  **/
qla4_82xx_queue_iocb(struct scsi_qla_host * ha)213f8086f4fSVikas Chaudhary void qla4_82xx_queue_iocb(struct scsi_qla_host *ha)
214f4f5df23SVikas Chaudhary {
215f4f5df23SVikas Chaudhary 	uint32_t dbval = 0;
216f4f5df23SVikas Chaudhary 
217f4f5df23SVikas Chaudhary 	dbval = 0x14 | (ha->func_num << 5);
218f4f5df23SVikas Chaudhary 	dbval = dbval | (0 << 8) | (ha->request_in << 16);
219f4f5df23SVikas Chaudhary 
220f8086f4fSVikas Chaudhary 	qla4_82xx_wr_32(ha, ha->nx_db_wr_ptr, ha->request_in);
221f4f5df23SVikas Chaudhary }
222f4f5df23SVikas Chaudhary 
223f4f5df23SVikas Chaudhary /**
224f8086f4fSVikas Chaudhary  * qla4_82xx_complete_iocb - Tell ISP we're done with response(s)
225f4f5df23SVikas Chaudhary  * @ha: pointer to host adapter structure.
226f4f5df23SVikas Chaudhary  *
227f4f5df23SVikas Chaudhary  * This routine notifies the ISP that one or more response/completion
228f4f5df23SVikas Chaudhary  * queue entries have been processed by the driver.
229f4f5df23SVikas Chaudhary  * This also clears the interrupt.
230f4f5df23SVikas Chaudhary  **/
qla4_82xx_complete_iocb(struct scsi_qla_host * ha)231f8086f4fSVikas Chaudhary void qla4_82xx_complete_iocb(struct scsi_qla_host *ha)
232f4f5df23SVikas Chaudhary {
2337664a1fdSVikas Chaudhary 	writel(ha->response_out, &ha->qla4_82xx_reg->rsp_q_out);
2347664a1fdSVikas Chaudhary 	readl(&ha->qla4_82xx_reg->rsp_q_out);
235f4f5df23SVikas Chaudhary }
236f4f5df23SVikas Chaudhary 
237f4f5df23SVikas Chaudhary /**
238f4f5df23SVikas Chaudhary  * qla4xxx_queue_iocb - Tell ISP it's got new request(s)
239f4f5df23SVikas Chaudhary  * @ha: pointer to host adapter structure.
240f4f5df23SVikas Chaudhary  *
241f4f5df23SVikas Chaudhary  * This routine is notifies the ISP that one or more new request
242f4f5df23SVikas Chaudhary  * queue entries have been placed on the request queue.
243f4f5df23SVikas Chaudhary  **/
qla4xxx_queue_iocb(struct scsi_qla_host * ha)244f4f5df23SVikas Chaudhary void qla4xxx_queue_iocb(struct scsi_qla_host *ha)
245f4f5df23SVikas Chaudhary {
246f4f5df23SVikas Chaudhary 	writel(ha->request_in, &ha->reg->req_q_in);
247f4f5df23SVikas Chaudhary 	readl(&ha->reg->req_q_in);
248f4f5df23SVikas Chaudhary }
249f4f5df23SVikas Chaudhary 
250f4f5df23SVikas Chaudhary /**
251f4f5df23SVikas Chaudhary  * qla4xxx_complete_iocb - Tell ISP we're done with response(s)
252f4f5df23SVikas Chaudhary  * @ha: pointer to host adapter structure.
253f4f5df23SVikas Chaudhary  *
254f4f5df23SVikas Chaudhary  * This routine is notifies the ISP that one or more response/completion
255f4f5df23SVikas Chaudhary  * queue entries have been processed by the driver.
256f4f5df23SVikas Chaudhary  * This also clears the interrupt.
257f4f5df23SVikas Chaudhary  **/
qla4xxx_complete_iocb(struct scsi_qla_host * ha)258f4f5df23SVikas Chaudhary void qla4xxx_complete_iocb(struct scsi_qla_host *ha)
259f4f5df23SVikas Chaudhary {
260f4f5df23SVikas Chaudhary 	writel(ha->response_out, &ha->reg->rsp_q_out);
261f4f5df23SVikas Chaudhary 	readl(&ha->reg->rsp_q_out);
262f4f5df23SVikas Chaudhary }
263f4f5df23SVikas Chaudhary 
264f4f5df23SVikas Chaudhary /**
265afaf5a2dSDavid Somayajulu  * qla4xxx_send_command_to_isp - issues command to HBA
266afaf5a2dSDavid Somayajulu  * @ha: pointer to host adapter structure.
267afaf5a2dSDavid Somayajulu  * @srb: pointer to SCSI Request Block to be sent to ISP
268afaf5a2dSDavid Somayajulu  *
269afaf5a2dSDavid Somayajulu  * This routine is called by qla4xxx_queuecommand to build an ISP
270afaf5a2dSDavid Somayajulu  * command and pass it to the ISP for execution.
271afaf5a2dSDavid Somayajulu  **/
qla4xxx_send_command_to_isp(struct scsi_qla_host * ha,struct srb * srb)272afaf5a2dSDavid Somayajulu int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
273afaf5a2dSDavid Somayajulu {
274afaf5a2dSDavid Somayajulu 	struct scsi_cmnd *cmd = srb->cmd;
275afaf5a2dSDavid Somayajulu 	struct ddb_entry *ddb_entry;
276afaf5a2dSDavid Somayajulu 	struct command_t3_entry *cmd_entry;
2775f7186c8SFUJITA Tomonori 	int nseg;
278afaf5a2dSDavid Somayajulu 	uint16_t tot_dsds;
279afaf5a2dSDavid Somayajulu 	uint16_t req_cnt;
280afaf5a2dSDavid Somayajulu 	unsigned long flags;
281afaf5a2dSDavid Somayajulu 	uint32_t index;
282afaf5a2dSDavid Somayajulu 
283afaf5a2dSDavid Somayajulu 	/* Get real lun and adapter */
284afaf5a2dSDavid Somayajulu 	ddb_entry = srb->ddb;
285afaf5a2dSDavid Somayajulu 
286afaf5a2dSDavid Somayajulu 	tot_dsds = 0;
287afaf5a2dSDavid Somayajulu 
288afaf5a2dSDavid Somayajulu 	/* Acquire hardware specific lock */
289afaf5a2dSDavid Somayajulu 	spin_lock_irqsave(&ha->hardware_lock, flags);
290afaf5a2dSDavid Somayajulu 
291*924b3d7aSBart Van Assche 	index = scsi_cmd_to_rq(cmd)->tag;
292afaf5a2dSDavid Somayajulu 
29316ed55f9SKaren Higgins 	/*
29416ed55f9SKaren Higgins 	 * Check to see if adapter is online before placing request on
29516ed55f9SKaren Higgins 	 * request queue.  If a reset occurs and a request is in the queue,
29616ed55f9SKaren Higgins 	 * the firmware will still attempt to process the request, retrieving
29716ed55f9SKaren Higgins 	 * garbage for pointers.
29816ed55f9SKaren Higgins 	 */
29916ed55f9SKaren Higgins 	if (!test_bit(AF_ONLINE, &ha->flags)) {
30016ed55f9SKaren Higgins 		DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
30116ed55f9SKaren Higgins 			      "Do not issue command.\n",
30216ed55f9SKaren Higgins 			      ha->host_no, __func__));
30316ed55f9SKaren Higgins 		goto queuing_error;
30416ed55f9SKaren Higgins 	}
30516ed55f9SKaren Higgins 
306afaf5a2dSDavid Somayajulu 	/* Calculate the number of request entries needed. */
3075f7186c8SFUJITA Tomonori 	nseg = scsi_dma_map(cmd);
3085f7186c8SFUJITA Tomonori 	if (nseg < 0)
309afaf5a2dSDavid Somayajulu 		goto queuing_error;
3105f7186c8SFUJITA Tomonori 	tot_dsds = nseg;
311afaf5a2dSDavid Somayajulu 
312afaf5a2dSDavid Somayajulu 	req_cnt = qla4xxx_calc_request_entries(tot_dsds);
31316ed55f9SKaren Higgins 	if (!qla4xxx_space_in_req_ring(ha, req_cnt))
314afaf5a2dSDavid Somayajulu 		goto queuing_error;
315afaf5a2dSDavid Somayajulu 
316afaf5a2dSDavid Somayajulu 	/* total iocbs active */
3175b1c1bffSKaren Higgins 	if ((ha->iocb_cnt + req_cnt) >= ha->iocb_hiwat)
318afaf5a2dSDavid Somayajulu 		goto queuing_error;
319afaf5a2dSDavid Somayajulu 
320afaf5a2dSDavid Somayajulu 	/* Build command packet */
321afaf5a2dSDavid Somayajulu 	cmd_entry = (struct command_t3_entry *) ha->request_ptr;
322afaf5a2dSDavid Somayajulu 	memset(cmd_entry, 0, sizeof(struct command_t3_entry));
323afaf5a2dSDavid Somayajulu 	cmd_entry->hdr.entryType = ET_COMMAND;
324afaf5a2dSDavid Somayajulu 	cmd_entry->handle = cpu_to_le32(index);
325afaf5a2dSDavid Somayajulu 	cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
326afaf5a2dSDavid Somayajulu 
327afaf5a2dSDavid Somayajulu 	int_to_scsilun(cmd->device->lun, &cmd_entry->lun);
3285f7186c8SFUJITA Tomonori 	cmd_entry->ttlByteCnt = cpu_to_le32(scsi_bufflen(cmd));
329afaf5a2dSDavid Somayajulu 	memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len);
330afaf5a2dSDavid Somayajulu 	cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds);
331afaf5a2dSDavid Somayajulu 	cmd_entry->hdr.entryCount = req_cnt;
332afaf5a2dSDavid Somayajulu 
333afaf5a2dSDavid Somayajulu 	/* Set data transfer direction control flags
334afaf5a2dSDavid Somayajulu 	 * NOTE: Look at data_direction bits iff there is data to be
335afaf5a2dSDavid Somayajulu 	 *	 transferred, as the data direction bit is sometimed filled
336afaf5a2dSDavid Somayajulu 	 *	 in when there is no data to be transferred */
337afaf5a2dSDavid Somayajulu 	cmd_entry->control_flags = CF_NO_DATA;
3385f7186c8SFUJITA Tomonori 	if (scsi_bufflen(cmd)) {
339afaf5a2dSDavid Somayajulu 		if (cmd->sc_data_direction == DMA_TO_DEVICE)
340afaf5a2dSDavid Somayajulu 			cmd_entry->control_flags = CF_WRITE;
341afaf5a2dSDavid Somayajulu 		else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
342afaf5a2dSDavid Somayajulu 			cmd_entry->control_flags = CF_READ;
343d915058fSDavid C Somayajulu 
3445f7186c8SFUJITA Tomonori 		ha->bytes_xfered += scsi_bufflen(cmd);
345d915058fSDavid C Somayajulu 		if (ha->bytes_xfered & ~0xFFFFF){
346d915058fSDavid C Somayajulu 			ha->total_mbytes_xferred += ha->bytes_xfered >> 20;
347d915058fSDavid C Somayajulu 			ha->bytes_xfered &= 0xFFFFF;
348d915058fSDavid C Somayajulu 		}
349afaf5a2dSDavid Somayajulu 	}
350afaf5a2dSDavid Somayajulu 
351afaf5a2dSDavid Somayajulu 	/* Set tagged queueing control flags */
352afaf5a2dSDavid Somayajulu 	cmd_entry->control_flags |= CF_SIMPLE_TAG;
353afaf5a2dSDavid Somayajulu 
35416ed55f9SKaren Higgins 	qla4xxx_advance_req_ring_ptr(ha);
355afaf5a2dSDavid Somayajulu 	qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
356afaf5a2dSDavid Somayajulu 	wmb();
357afaf5a2dSDavid Somayajulu 
3585369887aSVikas Chaudhary 	srb->cmd->host_scribble = (unsigned char *)(unsigned long)index;
359afaf5a2dSDavid Somayajulu 
360afaf5a2dSDavid Somayajulu 	/* update counters */
361afaf5a2dSDavid Somayajulu 	srb->state = SRB_ACTIVE_STATE;
362afaf5a2dSDavid Somayajulu 	srb->flags |= SRB_DMA_VALID;
363afaf5a2dSDavid Somayajulu 
364afaf5a2dSDavid Somayajulu 	/* Track IOCB used */
365afaf5a2dSDavid Somayajulu 	ha->iocb_cnt += req_cnt;
366afaf5a2dSDavid Somayajulu 	srb->iocb_cnt = req_cnt;
367afaf5a2dSDavid Somayajulu 	ha->req_q_count -= req_cnt;
368afaf5a2dSDavid Somayajulu 
369f4f5df23SVikas Chaudhary 	ha->isp_ops->queue_iocb(ha);
370afaf5a2dSDavid Somayajulu 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
371afaf5a2dSDavid Somayajulu 
372afaf5a2dSDavid Somayajulu 	return QLA_SUCCESS;
373afaf5a2dSDavid Somayajulu 
374afaf5a2dSDavid Somayajulu queuing_error:
3755f7186c8SFUJITA Tomonori 	if (tot_dsds)
3765f7186c8SFUJITA Tomonori 		scsi_dma_unmap(cmd);
377afaf5a2dSDavid Somayajulu 
378afaf5a2dSDavid Somayajulu 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
379afaf5a2dSDavid Somayajulu 
380afaf5a2dSDavid Somayajulu 	return QLA_ERROR;
381afaf5a2dSDavid Somayajulu }
382afaf5a2dSDavid Somayajulu 
qla4xxx_send_passthru0(struct iscsi_task * task)383b3a271a9SManish Rangankar int qla4xxx_send_passthru0(struct iscsi_task *task)
384b3a271a9SManish Rangankar {
385b3a271a9SManish Rangankar 	struct passthru0 *passthru_iocb;
386b3a271a9SManish Rangankar 	struct iscsi_session *sess = task->conn->session;
387b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry = sess->dd_data;
388b3a271a9SManish Rangankar 	struct scsi_qla_host *ha = ddb_entry->ha;
389b3a271a9SManish Rangankar 	struct ql4_task_data *task_data = task->dd_data;
390b3a271a9SManish Rangankar 	uint16_t ctrl_flags = 0;
391b3a271a9SManish Rangankar 	unsigned long flags;
392b3a271a9SManish Rangankar 	int ret = QLA_ERROR;
393b3a271a9SManish Rangankar 
394b3a271a9SManish Rangankar 	spin_lock_irqsave(&ha->hardware_lock, flags);
395b3a271a9SManish Rangankar 	task_data->iocb_req_cnt = 1;
396b3a271a9SManish Rangankar 	/* Put the IOCB on the request queue */
397b3a271a9SManish Rangankar 	if (!qla4xxx_space_in_req_ring(ha, task_data->iocb_req_cnt))
398b3a271a9SManish Rangankar 		goto queuing_error;
399b3a271a9SManish Rangankar 
400b3a271a9SManish Rangankar 	passthru_iocb = (struct passthru0 *) ha->request_ptr;
401b3a271a9SManish Rangankar 
402b3a271a9SManish Rangankar 	memset(passthru_iocb, 0, sizeof(struct passthru0));
403b3a271a9SManish Rangankar 	passthru_iocb->hdr.entryType = ET_PASSTHRU0;
404b3a271a9SManish Rangankar 	passthru_iocb->hdr.systemDefined = SD_ISCSI_PDU;
405b3a271a9SManish Rangankar 	passthru_iocb->hdr.entryCount = task_data->iocb_req_cnt;
406b3a271a9SManish Rangankar 	passthru_iocb->handle = task->itt;
407b3a271a9SManish Rangankar 	passthru_iocb->target = cpu_to_le16(ddb_entry->fw_ddb_index);
408b3a271a9SManish Rangankar 	passthru_iocb->timeout = cpu_to_le16(PT_DEFAULT_TIMEOUT);
409b3a271a9SManish Rangankar 
410b3a271a9SManish Rangankar 	/* Setup the out & in DSDs */
41169ca216eSManish Rangankar 	if (task_data->req_len) {
412b3a271a9SManish Rangankar 		memcpy((uint8_t *)task_data->req_buffer +
413b3a271a9SManish Rangankar 		       sizeof(struct iscsi_hdr), task->data, task->data_count);
414b3a271a9SManish Rangankar 		ctrl_flags |= PT_FLAG_SEND_BUFFER;
415b3a271a9SManish Rangankar 		passthru_iocb->out_dsd.base.addrLow =
416b3a271a9SManish Rangankar 					cpu_to_le32(LSDW(task_data->req_dma));
417b3a271a9SManish Rangankar 		passthru_iocb->out_dsd.base.addrHigh =
418b3a271a9SManish Rangankar 					cpu_to_le32(MSDW(task_data->req_dma));
419b3a271a9SManish Rangankar 		passthru_iocb->out_dsd.count =
420b3a271a9SManish Rangankar 					cpu_to_le32(task->data_count +
421b3a271a9SManish Rangankar 						    sizeof(struct iscsi_hdr));
422b3a271a9SManish Rangankar 	}
423b3a271a9SManish Rangankar 	if (task_data->resp_len) {
424b3a271a9SManish Rangankar 		passthru_iocb->in_dsd.base.addrLow =
425b3a271a9SManish Rangankar 					cpu_to_le32(LSDW(task_data->resp_dma));
426b3a271a9SManish Rangankar 		passthru_iocb->in_dsd.base.addrHigh =
427b3a271a9SManish Rangankar 					cpu_to_le32(MSDW(task_data->resp_dma));
428b3a271a9SManish Rangankar 		passthru_iocb->in_dsd.count =
429b3a271a9SManish Rangankar 			cpu_to_le32(task_data->resp_len);
430b3a271a9SManish Rangankar 	}
431b3a271a9SManish Rangankar 
432b3a271a9SManish Rangankar 	ctrl_flags |= (PT_FLAG_ISCSI_PDU | PT_FLAG_WAIT_4_RESPONSE);
433b3a271a9SManish Rangankar 	passthru_iocb->control_flags = cpu_to_le16(ctrl_flags);
434b3a271a9SManish Rangankar 
435b3a271a9SManish Rangankar 	/* Update the request pointer */
436b3a271a9SManish Rangankar 	qla4xxx_advance_req_ring_ptr(ha);
437b3a271a9SManish Rangankar 	wmb();
438b3a271a9SManish Rangankar 
439b3a271a9SManish Rangankar 	/* Track IOCB used */
440b3a271a9SManish Rangankar 	ha->iocb_cnt += task_data->iocb_req_cnt;
441b3a271a9SManish Rangankar 	ha->req_q_count -= task_data->iocb_req_cnt;
442b3a271a9SManish Rangankar 	ha->isp_ops->queue_iocb(ha);
443b3a271a9SManish Rangankar 	ret = QLA_SUCCESS;
444b3a271a9SManish Rangankar 
445b3a271a9SManish Rangankar queuing_error:
446b3a271a9SManish Rangankar 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
447b3a271a9SManish Rangankar 	return ret;
448b3a271a9SManish Rangankar }
449c0b9d3f7SVikas Chaudhary 
qla4xxx_get_new_mrb(struct scsi_qla_host * ha)450c0b9d3f7SVikas Chaudhary static struct mrb *qla4xxx_get_new_mrb(struct scsi_qla_host *ha)
451c0b9d3f7SVikas Chaudhary {
452c0b9d3f7SVikas Chaudhary 	struct mrb *mrb;
453c0b9d3f7SVikas Chaudhary 
454c0b9d3f7SVikas Chaudhary 	mrb = kzalloc(sizeof(*mrb), GFP_KERNEL);
455c0b9d3f7SVikas Chaudhary 	if (!mrb)
456c0b9d3f7SVikas Chaudhary 		return mrb;
457c0b9d3f7SVikas Chaudhary 
458c0b9d3f7SVikas Chaudhary 	mrb->ha = ha;
459c0b9d3f7SVikas Chaudhary 	return mrb;
460c0b9d3f7SVikas Chaudhary }
461c0b9d3f7SVikas Chaudhary 
qla4xxx_send_mbox_iocb(struct scsi_qla_host * ha,struct mrb * mrb,uint32_t * in_mbox)462a7380a65SVikas Chaudhary static int qla4xxx_send_mbox_iocb(struct scsi_qla_host *ha, struct mrb *mrb,
463c0b9d3f7SVikas Chaudhary 				  uint32_t *in_mbox)
464c0b9d3f7SVikas Chaudhary {
465c0b9d3f7SVikas Chaudhary 	int rval = QLA_SUCCESS;
466c0b9d3f7SVikas Chaudhary 	uint32_t i;
467c0b9d3f7SVikas Chaudhary 	unsigned long flags;
468c0b9d3f7SVikas Chaudhary 	uint32_t index = 0;
469c0b9d3f7SVikas Chaudhary 
470c0b9d3f7SVikas Chaudhary 	/* Acquire hardware specific lock */
471c0b9d3f7SVikas Chaudhary 	spin_lock_irqsave(&ha->hardware_lock, flags);
472c0b9d3f7SVikas Chaudhary 
473c0b9d3f7SVikas Chaudhary 	/* Get pointer to the queue entry for the marker */
474c0b9d3f7SVikas Chaudhary 	rval = qla4xxx_get_req_pkt(ha, (struct queue_entry **) &(mrb->mbox));
475c0b9d3f7SVikas Chaudhary 	if (rval != QLA_SUCCESS)
476c0b9d3f7SVikas Chaudhary 		goto exit_mbox_iocb;
477c0b9d3f7SVikas Chaudhary 
478c0b9d3f7SVikas Chaudhary 	index = ha->mrb_index;
479c0b9d3f7SVikas Chaudhary 	/* get valid mrb index*/
480c0b9d3f7SVikas Chaudhary 	for (i = 0; i < MAX_MRB; i++) {
481c0b9d3f7SVikas Chaudhary 		index++;
482c0b9d3f7SVikas Chaudhary 		if (index == MAX_MRB)
483c0b9d3f7SVikas Chaudhary 			index = 1;
484c0b9d3f7SVikas Chaudhary 		if (ha->active_mrb_array[index] == NULL) {
485c0b9d3f7SVikas Chaudhary 			ha->mrb_index = index;
486c0b9d3f7SVikas Chaudhary 			break;
487c0b9d3f7SVikas Chaudhary 		}
488c0b9d3f7SVikas Chaudhary 	}
489c0b9d3f7SVikas Chaudhary 
490c0b9d3f7SVikas Chaudhary 	mrb->iocb_cnt = 1;
491c0b9d3f7SVikas Chaudhary 	ha->active_mrb_array[index] = mrb;
492c0b9d3f7SVikas Chaudhary 	mrb->mbox->handle = index;
493c0b9d3f7SVikas Chaudhary 	mrb->mbox->hdr.entryType = ET_MBOX_CMD;
494c0b9d3f7SVikas Chaudhary 	mrb->mbox->hdr.entryCount = mrb->iocb_cnt;
495c0b9d3f7SVikas Chaudhary 	memcpy(mrb->mbox->in_mbox, in_mbox, 32);
496c0b9d3f7SVikas Chaudhary 	mrb->mbox_cmd = in_mbox[0];
497c0b9d3f7SVikas Chaudhary 	wmb();
498c0b9d3f7SVikas Chaudhary 
499d522844aSVikas Chaudhary 	ha->iocb_cnt += mrb->iocb_cnt;
500c0b9d3f7SVikas Chaudhary 	ha->isp_ops->queue_iocb(ha);
501c0b9d3f7SVikas Chaudhary exit_mbox_iocb:
502c0b9d3f7SVikas Chaudhary 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
503c0b9d3f7SVikas Chaudhary 	return rval;
504c0b9d3f7SVikas Chaudhary }
505c0b9d3f7SVikas Chaudhary 
qla4xxx_ping_iocb(struct scsi_qla_host * ha,uint32_t options,uint32_t payload_size,uint32_t pid,uint8_t * ipaddr)506c0b9d3f7SVikas Chaudhary int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
507c0b9d3f7SVikas Chaudhary 		      uint32_t payload_size, uint32_t pid, uint8_t *ipaddr)
508c0b9d3f7SVikas Chaudhary {
509c0b9d3f7SVikas Chaudhary 	uint32_t in_mbox[8];
510c0b9d3f7SVikas Chaudhary 	struct mrb *mrb = NULL;
511c0b9d3f7SVikas Chaudhary 	int rval = QLA_SUCCESS;
512c0b9d3f7SVikas Chaudhary 
513c0b9d3f7SVikas Chaudhary 	memset(in_mbox, 0, sizeof(in_mbox));
514c0b9d3f7SVikas Chaudhary 
515c0b9d3f7SVikas Chaudhary 	mrb = qla4xxx_get_new_mrb(ha);
516c0b9d3f7SVikas Chaudhary 	if (!mrb) {
517c0b9d3f7SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: fail to get new mrb\n",
518c0b9d3f7SVikas Chaudhary 				  __func__));
519c0b9d3f7SVikas Chaudhary 		rval = QLA_ERROR;
520c0b9d3f7SVikas Chaudhary 		goto exit_ping;
521c0b9d3f7SVikas Chaudhary 	}
522c0b9d3f7SVikas Chaudhary 
523c0b9d3f7SVikas Chaudhary 	in_mbox[0] = MBOX_CMD_PING;
524c0b9d3f7SVikas Chaudhary 	in_mbox[1] = options;
525c0b9d3f7SVikas Chaudhary 	memcpy(&in_mbox[2], &ipaddr[0], 4);
526c0b9d3f7SVikas Chaudhary 	memcpy(&in_mbox[3], &ipaddr[4], 4);
527c0b9d3f7SVikas Chaudhary 	memcpy(&in_mbox[4], &ipaddr[8], 4);
528c0b9d3f7SVikas Chaudhary 	memcpy(&in_mbox[5], &ipaddr[12], 4);
529c0b9d3f7SVikas Chaudhary 	in_mbox[6] = payload_size;
530c0b9d3f7SVikas Chaudhary 
531c0b9d3f7SVikas Chaudhary 	mrb->pid = pid;
532c0b9d3f7SVikas Chaudhary 	rval = qla4xxx_send_mbox_iocb(ha, mrb, in_mbox);
533c0b9d3f7SVikas Chaudhary 
534c0b9d3f7SVikas Chaudhary 	if (rval != QLA_SUCCESS)
535c0b9d3f7SVikas Chaudhary 		goto exit_ping;
536c0b9d3f7SVikas Chaudhary 
537c0b9d3f7SVikas Chaudhary 	return rval;
538c0b9d3f7SVikas Chaudhary exit_ping:
539c0b9d3f7SVikas Chaudhary 	kfree(mrb);
540c0b9d3f7SVikas Chaudhary 	return rval;
541c0b9d3f7SVikas Chaudhary }
542