blob: 9996ec0daab1666b26a5690f522bed06e31fd1dd [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Andrew Vasquezfa90c542005-10-27 11:10:08 -07002 * QLogic Fibre Channel HBA Driver
Armen Baloyanbd21eaf2014-04-11 16:54:24 -04003 * Copyright (c) 2003-2014 QLogic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Andrew Vasquezfa90c542005-10-27 11:10:08 -07005 * See LICENSE.qla2xxx for copyright and licensing details.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 */
7
Quinn Tranf83adb62014-04-11 16:54:43 -04008#include "qla_target.h"
Giridhar Malavali8ae6d9c2013-03-28 08:21:23 -04009/**
10 * qla24xx_calc_iocbs() - Determine number of Command Type 3 and
11 * Continuation Type 1 IOCBs to allocate.
12 *
13 * @dsds: number of data segment decriptors needed
14 *
15 * Returns the number of IOCB entries needed to store @dsds.
16 */
17static inline uint16_t
18qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
19{
20 uint16_t iocbs;
21
22 iocbs = 1;
23 if (dsds > 1) {
24 iocbs += (dsds - 1) / 5;
25 if ((dsds - 1) % 5)
26 iocbs++;
27 }
28 return iocbs;
29}
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031/*
32 * qla2x00_debounce_register
33 * Debounce register.
34 *
35 * Input:
36 * port = register address.
37 *
38 * Returns:
39 * register value.
40 */
41static __inline__ uint16_t
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -070042qla2x00_debounce_register(volatile uint16_t __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043{
44 volatile uint16_t first;
45 volatile uint16_t second;
46
47 do {
48 first = RD_REG_WORD(addr);
49 barrier();
50 cpu_relax();
51 second = RD_REG_WORD(addr);
52 } while (first != second);
53
54 return (first);
55}
56
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -070057static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080058qla2x00_poll(struct rsp_que *rsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059{
Andrew Vasquezd2ba5672008-05-12 22:21:14 -070060 unsigned long flags;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080061 struct qla_hw_data *ha = rsp->hw;
Andrew Vasquezd2ba5672008-05-12 22:21:14 -070062 local_irq_save(flags);
Atul Deshmukh7ec0eff2013-08-27 01:37:28 -040063 if (IS_P3P_TYPE(ha))
Giridhar Malavalia9083012010-04-12 17:59:55 -070064 qla82xx_poll(0, rsp);
65 else
66 ha->isp_ops->intr_handler(0, rsp);
Andrew Vasquezd2ba5672008-05-12 22:21:14 -070067 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068}
69
Andrew Vasquez2b6c0ce2005-07-06 10:31:17 -070070static inline uint8_t *
71host_to_fcp_swap(uint8_t *fcp, uint32_t bsize)
72{
73 uint32_t *ifcp = (uint32_t *) fcp;
74 uint32_t *ofcp = (uint32_t *) fcp;
75 uint32_t iter = bsize >> 2;
76
77 for (; iter ; iter--)
78 *ofcp++ = swab32(*ifcp++);
79
80 return fcp;
81}
Andrew Vasquez3d716442005-07-06 10:30:26 -070082
Chad Dupuis5f16b332012-08-22 14:21:00 -040083static inline void
Giridhar Malavali8ae6d9c2013-03-28 08:21:23 -040084host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
85{
86 uint32_t *isrc = (uint32_t *) src;
Saurav Kashyap1f8deef2013-06-25 11:27:21 -040087 __le32 *odest = (__le32 *) dst;
Giridhar Malavali8ae6d9c2013-03-28 08:21:23 -040088 uint32_t iter = bsize >> 2;
89
Joe Carnuccioda08ef52016-01-27 12:03:34 -050090 for ( ; iter--; isrc++)
91 *odest++ = cpu_to_le32(*isrc);
Giridhar Malavali8ae6d9c2013-03-28 08:21:23 -040092}
93
94static inline void
Chad Dupuis5f16b332012-08-22 14:21:00 -040095qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha)
96{
97 int i;
98
99 if (IS_FWI2_CAPABLE(ha))
100 return;
101
102 for (i = 0; i < SNS_FIRST_LOOP_ID; i++)
103 set_bit(i, ha->loop_id_map);
104 set_bit(MANAGEMENT_SERVER, ha->loop_id_map);
105 set_bit(BROADCAST, ha->loop_id_map);
106}
107
Andrew Vasquez3d716442005-07-06 10:30:26 -0700108static inline int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800109qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)
Andrew Vasquez3d716442005-07-06 10:30:26 -0700110{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800111 struct qla_hw_data *ha = vha->hw;
Andrew Vasqueze4289242007-07-19 15:05:56 -0700112 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez3d716442005-07-06 10:30:26 -0700113 return (loop_id > NPH_LAST_HANDLE);
114
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800115 return ((loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
Andrew Vasquez3d716442005-07-06 10:30:26 -0700116 loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST);
Anirban Chakraborty17d98632008-12-18 10:06:15 -0800117}
Arun Easibad75002010-05-04 15:01:30 -0700118
119static inline void
Chad Dupuis5f16b332012-08-22 14:21:00 -0400120qla2x00_clear_loop_id(fc_port_t *fcport) {
121 struct qla_hw_data *ha = fcport->vha->hw;
122
123 if (fcport->loop_id == FC_NO_LOOP_ID ||
124 qla2x00_is_reserved_id(fcport->vha, fcport->loop_id))
125 return;
126
127 clear_bit(fcport->loop_id, ha->loop_id_map);
128 fcport->loop_id = FC_NO_LOOP_ID;
129}
130
131static inline void
Joe Carnucciod5ff0ee2017-05-24 18:06:24 -0700132qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx)
Arun Easibad75002010-05-04 15:01:30 -0700133{
Joe Carnucciod5ff0ee2017-05-24 18:06:24 -0700134 struct dsd_dma *dsd, *tdsd;
Arun Easibad75002010-05-04 15:01:30 -0700135
136 /* clean up allocated prev pool */
Joe Carnucciod5ff0ee2017-05-24 18:06:24 -0700137 list_for_each_entry_safe(dsd, tdsd, &ctx->dsd_list, list) {
138 dma_pool_free(ha->dl_dma_pool, dsd->dsd_addr,
139 dsd->dsd_list_dma);
140 list_del(&dsd->list);
141 kfree(dsd);
Arun Easibad75002010-05-04 15:01:30 -0700142 }
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800143 INIT_LIST_HEAD(&ctx->dsd_list);
Arun Easibad75002010-05-04 15:01:30 -0700144}
Chad Dupuisec426e12011-03-30 11:46:32 -0700145
146static inline void
147qla2x00_set_fcport_state(fc_port_t *fcport, int state)
148{
149 int old_state;
150
151 old_state = atomic_read(&fcport->state);
152 atomic_set(&fcport->state, state);
153
154 /* Don't print state transitions during initial allocation of fcport */
155 if (old_state && old_state != state) {
Saurav Kashyap7c3df132011-07-14 12:00:13 -0700156 ql_dbg(ql_dbg_disc, fcport->vha, 0x207d,
Quinn Tran726b8542017-01-19 22:28:00 -0800157 "FCPort %8phC state transitioned from %s to %s - "
158 "portid=%02x%02x%02x.\n", fcport->port_name,
Chad Dupuisec426e12011-03-30 11:46:32 -0700159 port_state_str[old_state], port_state_str[state],
160 fcport->d_id.b.domain, fcport->d_id.b.area,
Saurav Kashyap7c3df132011-07-14 12:00:13 -0700161 fcport->d_id.b.al_pa);
Chad Dupuisec426e12011-03-30 11:46:32 -0700162 }
163}
Arun Easi8cb20492011-08-16 11:29:22 -0700164
165static inline int
Arun Easie02587d2011-08-16 11:29:23 -0700166qla2x00_hba_err_chk_enabled(srb_t *sp)
Arun Easi8cb20492011-08-16 11:29:22 -0700167{
Arun Easie02587d2011-08-16 11:29:23 -0700168 /*
169 * Uncomment when corresponding SCSI changes are done.
170 *
171 if (!sp->cmd->prot_chk)
172 return 0;
173 *
174 */
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800175 switch (scsi_get_prot_op(GET_CMD_SP(sp))) {
Arun Easi8cb20492011-08-16 11:29:22 -0700176 case SCSI_PROT_READ_STRIP:
177 case SCSI_PROT_WRITE_INSERT:
178 if (ql2xenablehba_err_chk >= 1)
179 return 1;
180 break;
181 case SCSI_PROT_READ_PASS:
182 case SCSI_PROT_WRITE_PASS:
183 if (ql2xenablehba_err_chk >= 2)
184 return 1;
185 break;
186 case SCSI_PROT_READ_INSERT:
187 case SCSI_PROT_WRITE_STRIP:
188 return 1;
189 }
190 return 0;
191}
Andrew Vasquezd051a5aa2012-02-09 11:14:05 -0800192
193static inline int
194qla2x00_reset_active(scsi_qla_host_t *vha)
195{
196 scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev);
197
198 /* Test appropriate base-vha and vha flags. */
199 return test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) ||
200 test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) ||
201 test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) ||
202 test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
203 test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
204}
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800205
206static inline srb_t *
Michael Hernandezd7459522016-12-12 14:40:07 -0800207qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag)
208{
209 srb_t *sp = NULL;
210 uint8_t bail;
211
212 QLA_QPAIR_MARK_BUSY(qpair, bail);
213 if (unlikely(bail))
214 return NULL;
215
216 sp = mempool_alloc(qpair->srb_mempool, flag);
217 if (!sp)
218 goto done;
219
220 memset(sp, 0, sizeof(*sp));
221 sp->fcport = fcport;
222 sp->iocbs = 1;
Joe Carnuccio25ff6af2017-01-19 22:28:04 -0800223 sp->vha = qpair->vha;
Michael Hernandezd7459522016-12-12 14:40:07 -0800224done:
225 if (!sp)
226 QLA_QPAIR_MARK_NOT_BUSY(qpair);
227 return sp;
228}
229
230static inline void
231qla2xxx_rel_qpair_sp(struct qla_qpair *qpair, srb_t *sp)
232{
233 mempool_free(sp, qpair->srb_mempool);
234 QLA_QPAIR_MARK_NOT_BUSY(qpair);
235}
236
237static inline srb_t *
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800238qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag)
239{
240 srb_t *sp = NULL;
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800241 uint8_t bail;
242
243 QLA_VHA_MARK_BUSY(vha, bail);
244 if (unlikely(bail))
245 return NULL;
246
Joe Carnuccio25ff6af2017-01-19 22:28:04 -0800247 sp = mempool_alloc(vha->hw->srb_mempool, flag);
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800248 if (!sp)
249 goto done;
250
251 memset(sp, 0, sizeof(*sp));
252 sp->fcport = fcport;
253 sp->iocbs = 1;
Quinn Tran726b8542017-01-19 22:28:00 -0800254 sp->vha = vha;
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800255done:
256 if (!sp)
257 QLA_VHA_MARK_NOT_BUSY(vha);
258 return sp;
259}
260
261static inline void
Joe Carnuccio25ff6af2017-01-19 22:28:04 -0800262qla2x00_rel_sp(srb_t *sp)
Chad Dupuisb00ee7d2013-02-08 01:57:50 -0500263{
Joe Carnuccio25ff6af2017-01-19 22:28:04 -0800264 QLA_VHA_MARK_NOT_BUSY(sp->vha);
265 mempool_free(sp, sp->vha->hw->srb_mempool);
Chad Dupuisb00ee7d2013-02-08 01:57:50 -0500266}
267
268static inline void
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800269qla2x00_init_timer(srb_t *sp, unsigned long tmo)
270{
271 init_timer(&sp->u.iocb_cmd.timer);
272 sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ;
273 sp->u.iocb_cmd.timer.data = (unsigned long)sp;
274 sp->u.iocb_cmd.timer.function = qla2x00_sp_timeout;
275 add_timer(&sp->u.iocb_cmd.timer);
276 sp->free = qla2x00_sp_free;
Joe Carnuccio25ff6af2017-01-19 22:28:04 -0800277 if (IS_QLAFX00(sp->vha->hw) && (sp->type == SRB_FXIOCB_DCMD))
Giridhar Malavali8ae6d9c2013-03-28 08:21:23 -0400278 init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
Himanshu Madhani6eb54712015-12-17 14:57:00 -0500279 if (sp->type == SRB_ELS_DCMD)
280 init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
Giridhar Malavali9ba56b92012-02-09 11:15:36 -0800281}
Chad Dupuis642ef982012-02-09 11:15:57 -0800282
283static inline int
284qla2x00_gid_list_size(struct qla_hw_data *ha)
285{
Giridhar Malavali8ae6d9c2013-03-28 08:21:23 -0400286 if (IS_QLAFX00(ha))
287 return sizeof(uint32_t) * 32;
288 else
289 return sizeof(struct gid_list_info) * ha->max_fibre_devices;
Chad Dupuis642ef982012-02-09 11:15:57 -0800290}
Chad Dupuis3c290d02013-01-30 03:34:38 -0500291
292static inline void
gurinder.shergill@hp.com36439832013-04-23 10:13:17 -0700293qla2x00_handle_mbx_completion(struct qla_hw_data *ha, int status)
294{
295 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
296 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
297 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
298 clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
299 complete(&ha->mbx_intr_comp);
300 }
301}
Chad Dupuise05fe292014-09-25 05:16:59 -0400302
303static inline void
304qla2x00_set_retry_delay_timestamp(fc_port_t *fcport, uint16_t retry_delay)
305{
306 if (retry_delay)
307 fcport->retry_delay_timestamp = jiffies +
308 (retry_delay * HZ / 10);
309}
Quinn Tran99e1b682017-06-02 09:12:03 -0700310
311static inline bool
312qla_is_exch_offld_enabled(struct scsi_qla_host *vha)
313{
314 if (qla_ini_mode_enabled(vha) &&
315 (ql2xiniexchg > FW_DEF_EXCHANGES_CNT))
316 return true;
317 else if (qla_tgt_mode_enabled(vha) &&
318 (ql2xexchoffld > FW_DEF_EXCHANGES_CNT))
319 return true;
320 else if (qla_dual_mode_enabled(vha) &&
321 ((ql2xiniexchg + ql2xexchoffld) > FW_DEF_EXCHANGES_CNT))
322 return true;
323 else
324 return false;
325}