blob: 12fc6ebbc2443c018cb7d05a09b2f090cae0a947 [file] [log] [blame]
Christof Schmitt4318e082009-11-24 16:54:08 +01001/*
2 * zfcp device driver
3 *
4 * Fibre Channel related definitions and inline functions for the zfcp
5 * device driver
6 *
7 * Copyright IBM Corporation 2009
8 */
9
10#ifndef ZFCP_FC_H
11#define ZFCP_FC_H
12
Christof Schmitt9d05ce22009-11-24 16:54:09 +010013#include <scsi/fc/fc_els.h>
Christof Schmitt4318e082009-11-24 16:54:08 +010014#include <scsi/fc/fc_fcp.h>
Christof Schmittdbf5dfe2009-11-24 16:54:10 +010015#include <scsi/fc/fc_ns.h>
Christof Schmitt4318e082009-11-24 16:54:08 +010016#include <scsi/scsi_cmnd.h>
17#include <scsi/scsi_tcq.h>
18
Christof Schmittdbf5dfe2009-11-24 16:54:10 +010019#define ZFCP_FC_CT_SIZE_PAGE (PAGE_SIZE - sizeof(struct fc_ct_hdr))
20#define ZFCP_FC_GPN_FT_ENT_PAGE (ZFCP_FC_CT_SIZE_PAGE \
21 / sizeof(struct fc_gpn_ft_resp))
22#define ZFCP_FC_GPN_FT_NUM_BUFS 4 /* memory pages */
23
24#define ZFCP_FC_GPN_FT_MAX_SIZE (ZFCP_FC_GPN_FT_NUM_BUFS * PAGE_SIZE \
25 - sizeof(struct fc_ct_hdr))
26#define ZFCP_FC_GPN_FT_MAX_ENT (ZFCP_FC_GPN_FT_NUM_BUFS * \
27 (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
28
29/**
30 * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
31 * @ct_hdr: FC GS common transport header
32 * @gid_pn: GID_PN request
33 */
34struct zfcp_fc_gid_pn_req {
35 struct fc_ct_hdr ct_hdr;
36 struct fc_ns_gid_pn gid_pn;
37} __packed;
38
39/**
40 * struct zfcp_fc_gid_pn_resp - container for ct header plus gid_pn response
41 * @ct_hdr: FC GS common transport header
42 * @gid_pn: GID_PN response
43 */
44struct zfcp_fc_gid_pn_resp {
45 struct fc_ct_hdr ct_hdr;
46 struct fc_gid_pn_resp gid_pn;
47} __packed;
48
49/**
50 * struct zfcp_fc_gid_pn - everything required in zfcp for gid_pn request
51 * @ct: data passed to zfcp_fsf for issuing fsf request
52 * @sg_req: scatterlist entry for request data
53 * @sg_resp: scatterlist entry for response data
54 * @gid_pn_req: GID_PN request data
55 * @gid_pn_resp: GID_PN response data
56 */
57struct zfcp_fc_gid_pn {
58 struct zfcp_send_ct ct;
59 struct scatterlist sg_req;
60 struct scatterlist sg_resp;
61 struct zfcp_fc_gid_pn_req gid_pn_req;
62 struct zfcp_fc_gid_pn_resp gid_pn_resp;
63 struct zfcp_port *port;
64};
65
66/**
67 * struct zfcp_fc_gpn_ft - container for ct header plus gpn_ft request
68 * @ct_hdr: FC GS common transport header
69 * @gpn_ft: GPN_FT request
70 */
71struct zfcp_fc_gpn_ft_req {
72 struct fc_ct_hdr ct_hdr;
73 struct fc_ns_gid_ft gpn_ft;
74} __packed;
75
76/**
77 * struct zfcp_fc_gpn_ft_resp - container for ct header plus gpn_ft response
78 * @ct_hdr: FC GS common transport header
79 * @gpn_ft: Array of gpn_ft response data to fill one memory page
80 */
81struct zfcp_fc_gpn_ft_resp {
82 struct fc_ct_hdr ct_hdr;
83 struct fc_gpn_ft_resp gpn_ft[ZFCP_FC_GPN_FT_ENT_PAGE];
84} __packed;
85
86/**
87 * struct zfcp_fc_gpn_ft - zfcp data for gpn_ft request
88 * @ct: data passed to zfcp_fsf for issuing fsf request
89 * @sg_req: scatter list entry for gpn_ft request
90 * @sg_resp: scatter list entries for gpn_ft responses (per memory page)
91 */
92struct zfcp_fc_gpn_ft {
93 struct zfcp_send_ct ct;
94 struct scatterlist sg_req;
95 struct scatterlist sg_resp[ZFCP_FC_GPN_FT_NUM_BUFS];
96};
97
Christof Schmitt4318e082009-11-24 16:54:08 +010098/**
Christof Schmitt9d05ce22009-11-24 16:54:09 +010099 * struct zfcp_fc_els_adisc - everything required in zfcp for issuing ELS ADISC
100 * @els: data required for issuing els fsf command
101 * @req: scatterlist entry for ELS ADISC request
102 * @resp: scatterlist entry for ELS ADISC response
103 * @adisc_req: ELS ADISC request data
104 * @adisc_resp: ELS ADISC response data
105 */
106struct zfcp_fc_els_adisc {
107 struct zfcp_send_els els;
108 struct scatterlist req;
109 struct scatterlist resp;
110 struct fc_els_adisc adisc_req;
111 struct fc_els_adisc adisc_resp;
112};
113
114/**
Christof Schmitt4318e082009-11-24 16:54:08 +0100115 * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd
116 * @fcp: fcp_cmnd to setup
117 * @scsi: scsi_cmnd where to get LUN, task attributes/flags and CDB
118 */
119static inline
120void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
121{
122 char tag[2];
123
124 int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun);
125
126 if (scsi_populate_tag_msg(scsi, tag)) {
127 switch (tag[0]) {
128 case MSG_ORDERED_TAG:
129 fcp->fc_pri_ta |= FCP_PTA_ORDERED;
130 break;
131 case MSG_SIMPLE_TAG:
132 fcp->fc_pri_ta |= FCP_PTA_SIMPLE;
133 break;
134 };
135 } else
136 fcp->fc_pri_ta = FCP_PTA_SIMPLE;
137
138 if (scsi->sc_data_direction == DMA_FROM_DEVICE)
139 fcp->fc_flags |= FCP_CFL_RDDATA;
140 if (scsi->sc_data_direction == DMA_TO_DEVICE)
141 fcp->fc_flags |= FCP_CFL_WRDATA;
142
143 memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
144
145 fcp->fc_dl = scsi_bufflen(scsi);
146}
147
148/**
149 * zfcp_fc_fcp_tm - setup FCP command as task management command
150 * @fcp: fcp_cmnd to setup
151 * @dev: scsi_device where to send the task management command
152 * @tm: task management flags to setup tm command
153 */
154static inline
155void zfcp_fc_fcp_tm(struct fcp_cmnd *fcp, struct scsi_device *dev, u8 tm_flags)
156{
157 int_to_scsilun(dev->lun, (struct scsi_lun *) &fcp->fc_lun);
158 fcp->fc_tm_flags |= tm_flags;
159}
160
161/**
162 * zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly
163 * @fcp_rsp: FCP RSP IU to evaluate
164 * @scsi: SCSI command where to update status and sense buffer
165 */
166static inline
167void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
168 struct scsi_cmnd *scsi)
169{
170 struct fcp_resp_rsp_info *rsp_info;
171 char *sense;
172 u32 sense_len, resid;
173 u8 rsp_flags;
174
175 set_msg_byte(scsi, COMMAND_COMPLETE);
176 scsi->result |= fcp_rsp->resp.fr_status;
177
178 rsp_flags = fcp_rsp->resp.fr_flags;
179
180 if (unlikely(rsp_flags & FCP_RSP_LEN_VAL)) {
181 rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
182 if (rsp_info->rsp_code == FCP_TMF_CMPL)
183 set_host_byte(scsi, DID_OK);
184 else {
185 set_host_byte(scsi, DID_ERROR);
186 return;
187 }
188 }
189
190 if (unlikely(rsp_flags & FCP_SNS_LEN_VAL)) {
191 sense = (char *) &fcp_rsp[1];
192 if (rsp_flags & FCP_RSP_LEN_VAL)
193 sense += fcp_rsp->ext.fr_sns_len;
194 sense_len = min(fcp_rsp->ext.fr_sns_len,
195 (u32) SCSI_SENSE_BUFFERSIZE);
196 memcpy(scsi->sense_buffer, sense, sense_len);
197 }
198
199 if (unlikely(rsp_flags & FCP_RESID_UNDER)) {
200 resid = fcp_rsp->ext.fr_resid;
201 scsi_set_resid(scsi, resid);
202 if (scsi_bufflen(scsi) - resid < scsi->underflow &&
203 !(rsp_flags & FCP_SNS_LEN_VAL) &&
204 fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
205 set_host_byte(scsi, DID_ERROR);
206 }
207}
208
209#endif