diff options
author | Yi Zou <yi.zou@intel.com> | 2009-02-27 17:07:21 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-13 16:15:15 -0400 |
commit | b277d2aa9a4d969002c4157bf77b76b9ad9ca04a (patch) | |
tree | 1054ff4ab2d03eaaa527919380ed6334233f632b | |
parent | 39ca9a065a5a0a6f2f0cd648090a979ba3f4f018 (diff) |
[SCSI] libfc: add support of large receive offload by ddp in fc_fcp
When LLD supports direct data placement (ddp) for large receive of an scsi
i/o coming into fc_fcp, we call into libfc_function_template's ddp_setup()
to prepare for a ddp of large receive for this read I/O. When I/O is complete,
we call the corresponding ddp_done() to get the length of data ddped as well
as to let LLD do clean up.
fc_fcp_ddp_setup()/fc_fcp_ddp_done() are added to setup and complete a ddped
read I/O described by the given fc_fcp_pkt. They would call into corresponding
ddp_setup/ddp_done implemented by the fcoe layer. Eventually, fcoe layer calls
into LLD's ddp_setup/ddp_done provided through net_device
Signed-off-by: Yi Zou <yi.zou@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 4 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_fcp.c | 61 | ||||
-rw-r--r-- | include/scsi/fc_frame.h | 19 | ||||
-rw-r--r-- | include/scsi/libfc.h | 30 | ||||
-rw-r--r-- | include/scsi/libfcoe.h | 18 |
5 files changed, 95 insertions, 37 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 8a0c5c239e9c..992af05aacf1 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c | |||
@@ -489,7 +489,7 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) | |||
489 | struct fc_exch *ep = NULL; | 489 | struct fc_exch *ep = NULL; |
490 | 490 | ||
491 | if (mp->max_read) { | 491 | if (mp->max_read) { |
492 | if (fc_frame_is_read(fp)) { | 492 | if (fc_fcp_is_read(fr_fsp(fp))) { |
493 | min = mp->min_xid; | 493 | min = mp->min_xid; |
494 | max = mp->max_read; | 494 | max = mp->max_read; |
495 | plast = &mp->last_read; | 495 | plast = &mp->last_read; |
@@ -1841,6 +1841,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, | |||
1841 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); | 1841 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); |
1842 | sp->cnt++; | 1842 | sp->cnt++; |
1843 | 1843 | ||
1844 | fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); | ||
1845 | |||
1844 | if (unlikely(lp->tt.frame_send(lp, fp))) | 1846 | if (unlikely(lp->tt.frame_send(lp, fp))) |
1845 | goto err; | 1847 | goto err; |
1846 | 1848 | ||
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 48adb89d911a..a5725f3b7ce1 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c | |||
@@ -265,6 +265,56 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp) | |||
265 | } | 265 | } |
266 | 266 | ||
267 | /* | 267 | /* |
268 | * fc_fcp_ddp_setup - calls to LLD's ddp_setup to set up DDP | ||
269 | * transfer for a read I/O indicated by the fc_fcp_pkt. | ||
270 | * @fsp: ptr to the fc_fcp_pkt | ||
271 | * | ||
272 | * This is called in exch_seq_send() when we have a newly allocated | ||
273 | * exchange with a valid exchange id to setup ddp. | ||
274 | * | ||
275 | * returns: none | ||
276 | */ | ||
277 | void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid) | ||
278 | { | ||
279 | struct fc_lport *lp; | ||
280 | |||
281 | if (!fsp) | ||
282 | return; | ||
283 | |||
284 | lp = fsp->lp; | ||
285 | if ((fsp->req_flags & FC_SRB_READ) && | ||
286 | (lp->lro_enabled) && (lp->tt.ddp_setup)) { | ||
287 | if (lp->tt.ddp_setup(lp, xid, scsi_sglist(fsp->cmd), | ||
288 | scsi_sg_count(fsp->cmd))) | ||
289 | fsp->xfer_ddp = xid; | ||
290 | } | ||
291 | } | ||
292 | EXPORT_SYMBOL(fc_fcp_ddp_setup); | ||
293 | |||
294 | /* | ||
295 | * fc_fcp_ddp_done - calls to LLD's ddp_done to release any | ||
296 | * DDP related resources for this I/O if it is initialized | ||
297 | * as a ddp transfer | ||
298 | * @fsp: ptr to the fc_fcp_pkt | ||
299 | * | ||
300 | * returns: none | ||
301 | */ | ||
302 | static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp) | ||
303 | { | ||
304 | struct fc_lport *lp; | ||
305 | |||
306 | if (!fsp) | ||
307 | return; | ||
308 | |||
309 | lp = fsp->lp; | ||
310 | if (fsp->xfer_ddp && lp->tt.ddp_done) { | ||
311 | fsp->xfer_len = lp->tt.ddp_done(lp, fsp->xfer_ddp); | ||
312 | fsp->xfer_ddp = 0; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | |||
317 | /* | ||
268 | * Receive SCSI data from target. | 318 | * Receive SCSI data from target. |
269 | * Called after receiving solicited data. | 319 | * Called after receiving solicited data. |
270 | */ | 320 | */ |
@@ -289,6 +339,9 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
289 | len = fr_len(fp) - sizeof(*fh); | 339 | len = fr_len(fp) - sizeof(*fh); |
290 | buf = fc_frame_payload_get(fp, 0); | 340 | buf = fc_frame_payload_get(fp, 0); |
291 | 341 | ||
342 | /* if this I/O is ddped, update xfer len */ | ||
343 | fc_fcp_ddp_done(fsp); | ||
344 | |||
292 | if (offset + len > fsp->data_len) { | 345 | if (offset + len > fsp->data_len) { |
293 | /* this should never happen */ | 346 | /* this should never happen */ |
294 | if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && | 347 | if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && |
@@ -750,6 +803,9 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
750 | fsp->scsi_comp_flags = flags; | 803 | fsp->scsi_comp_flags = flags; |
751 | expected_len = fsp->data_len; | 804 | expected_len = fsp->data_len; |
752 | 805 | ||
806 | /* if ddp, update xfer len */ | ||
807 | fc_fcp_ddp_done(fsp); | ||
808 | |||
753 | if (unlikely((flags & ~FCP_CONF_REQ) || fc_rp->fr_status)) { | 809 | if (unlikely((flags & ~FCP_CONF_REQ) || fc_rp->fr_status)) { |
754 | rp_ex = (void *)(fc_rp + 1); | 810 | rp_ex = (void *)(fc_rp + 1); |
755 | if (flags & (FCP_RSP_LEN_VAL | FCP_SNS_LEN_VAL)) { | 811 | if (flags & (FCP_RSP_LEN_VAL | FCP_SNS_LEN_VAL)) { |
@@ -1012,7 +1068,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp, | |||
1012 | } | 1068 | } |
1013 | 1069 | ||
1014 | memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); | 1070 | memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); |
1015 | fr_cmd(fp) = fsp->cmd; | 1071 | fr_fsp(fp) = fsp; |
1016 | rport = fsp->rport; | 1072 | rport = fsp->rport; |
1017 | fsp->max_payload = rport->maxframe_size; | 1073 | fsp->max_payload = rport->maxframe_size; |
1018 | rp = rport->dd_data; | 1074 | rp = rport->dd_data; |
@@ -1746,6 +1802,9 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) | |||
1746 | struct fc_lport *lp; | 1802 | struct fc_lport *lp; |
1747 | unsigned long flags; | 1803 | unsigned long flags; |
1748 | 1804 | ||
1805 | /* release outstanding ddp context */ | ||
1806 | fc_fcp_ddp_done(fsp); | ||
1807 | |||
1749 | fsp->state |= FC_SRB_COMPL; | 1808 | fsp->state |= FC_SRB_COMPL; |
1750 | if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) { | 1809 | if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) { |
1751 | spin_unlock_bh(&fsp->scsi_pkt_lock); | 1810 | spin_unlock_bh(&fsp->scsi_pkt_lock); |
diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h index 04d34a71355f..59511057cee0 100644 --- a/include/scsi/fc_frame.h +++ b/include/scsi/fc_frame.h | |||
@@ -54,8 +54,7 @@ | |||
54 | #define fr_eof(fp) (fr_cb(fp)->fr_eof) | 54 | #define fr_eof(fp) (fr_cb(fp)->fr_eof) |
55 | #define fr_flags(fp) (fr_cb(fp)->fr_flags) | 55 | #define fr_flags(fp) (fr_cb(fp)->fr_flags) |
56 | #define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload) | 56 | #define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload) |
57 | #define fr_cmd(fp) (fr_cb(fp)->fr_cmd) | 57 | #define fr_fsp(fp) (fr_cb(fp)->fr_fsp) |
58 | #define fr_dir(fp) (fr_cmd(fp)->sc_data_direction) | ||
59 | #define fr_crc(fp) (fr_cb(fp)->fr_crc) | 58 | #define fr_crc(fp) (fr_cb(fp)->fr_crc) |
60 | 59 | ||
61 | struct fc_frame { | 60 | struct fc_frame { |
@@ -66,7 +65,7 @@ struct fcoe_rcv_info { | |||
66 | struct packet_type *ptype; | 65 | struct packet_type *ptype; |
67 | struct fc_lport *fr_dev; /* transport layer private pointer */ | 66 | struct fc_lport *fr_dev; /* transport layer private pointer */ |
68 | struct fc_seq *fr_seq; /* for use with exchange manager */ | 67 | struct fc_seq *fr_seq; /* for use with exchange manager */ |
69 | struct scsi_cmnd *fr_cmd; /* for use of scsi command */ | 68 | struct fc_fcp_pkt *fr_fsp; /* for the corresponding fcp I/O */ |
70 | u32 fr_crc; | 69 | u32 fr_crc; |
71 | u16 fr_max_payload; /* max FC payload */ | 70 | u16 fr_max_payload; /* max FC payload */ |
72 | enum fc_sof fr_sof; /* start of frame delimiter */ | 71 | enum fc_sof fr_sof; /* start of frame delimiter */ |
@@ -218,20 +217,6 @@ static inline bool fc_frame_is_cmd(const struct fc_frame *fp) | |||
218 | return fc_frame_rctl(fp) == FC_RCTL_DD_UNSOL_CMD; | 217 | return fc_frame_rctl(fp) == FC_RCTL_DD_UNSOL_CMD; |
219 | } | 218 | } |
220 | 219 | ||
221 | static inline bool fc_frame_is_read(const struct fc_frame *fp) | ||
222 | { | ||
223 | if (fc_frame_is_cmd(fp) && fr_cmd(fp)) | ||
224 | return fr_dir(fp) == DMA_FROM_DEVICE; | ||
225 | return false; | ||
226 | } | ||
227 | |||
228 | static inline bool fc_frame_is_write(const struct fc_frame *fp) | ||
229 | { | ||
230 | if (fc_frame_is_cmd(fp) && fr_cmd(fp)) | ||
231 | return fr_dir(fp) == DMA_TO_DEVICE; | ||
232 | return false; | ||
233 | } | ||
234 | |||
235 | /* | 220 | /* |
236 | * Check for leaks. | 221 | * Check for leaks. |
237 | * Print the frame header of any currently allocated frame, assuming there | 222 | * Print the frame header of any currently allocated frame, assuming there |
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 61c746cf55f3..a70eafaad084 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h | |||
@@ -245,6 +245,7 @@ struct fc_fcp_pkt { | |||
245 | */ | 245 | */ |
246 | struct fcp_cmnd cdb_cmd; | 246 | struct fcp_cmnd cdb_cmd; |
247 | size_t xfer_len; | 247 | size_t xfer_len; |
248 | u16 xfer_ddp; /* this xfer is ddped */ | ||
248 | u32 xfer_contig_end; /* offset of end of contiguous xfer */ | 249 | u32 xfer_contig_end; /* offset of end of contiguous xfer */ |
249 | u16 max_payload; /* max payload size in bytes */ | 250 | u16 max_payload; /* max payload size in bytes */ |
250 | 251 | ||
@@ -267,6 +268,15 @@ struct fc_fcp_pkt { | |||
267 | u8 recov_retry; /* count of recovery retries */ | 268 | u8 recov_retry; /* count of recovery retries */ |
268 | struct fc_seq *recov_seq; /* sequence for REC or SRR */ | 269 | struct fc_seq *recov_seq; /* sequence for REC or SRR */ |
269 | }; | 270 | }; |
271 | /* | ||
272 | * FC_FCP HELPER FUNCTIONS | ||
273 | *****************************/ | ||
274 | static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp) | ||
275 | { | ||
276 | if (fsp && fsp->cmd) | ||
277 | return fsp->cmd->sc_data_direction == DMA_FROM_DEVICE; | ||
278 | return false; | ||
279 | } | ||
270 | 280 | ||
271 | /* | 281 | /* |
272 | * Structure and function definitions for managing Fibre Channel Exchanges | 282 | * Structure and function definitions for managing Fibre Channel Exchanges |
@@ -400,6 +410,21 @@ struct libfc_function_template { | |||
400 | void *arg, unsigned int timer_msec); | 410 | void *arg, unsigned int timer_msec); |
401 | 411 | ||
402 | /* | 412 | /* |
413 | * Sets up the DDP context for a given exchange id on the given | ||
414 | * scatterlist if LLD supports DDP for large receive. | ||
415 | * | ||
416 | * STATUS: OPTIONAL | ||
417 | */ | ||
418 | int (*ddp_setup)(struct fc_lport *lp, u16 xid, | ||
419 | struct scatterlist *sgl, unsigned int sgc); | ||
420 | /* | ||
421 | * Completes the DDP transfer and returns the length of data DDPed | ||
422 | * for the given exchange id. | ||
423 | * | ||
424 | * STATUS: OPTIONAL | ||
425 | */ | ||
426 | int (*ddp_done)(struct fc_lport *lp, u16 xid); | ||
427 | /* | ||
403 | * Send a frame using an existing sequence and exchange. | 428 | * Send a frame using an existing sequence and exchange. |
404 | * | 429 | * |
405 | * STATUS: OPTIONAL | 430 | * STATUS: OPTIONAL |
@@ -822,6 +847,11 @@ int fc_change_queue_type(struct scsi_device *sdev, int tag_type); | |||
822 | void fc_fcp_destroy(struct fc_lport *); | 847 | void fc_fcp_destroy(struct fc_lport *); |
823 | 848 | ||
824 | /* | 849 | /* |
850 | * Set up direct-data placement for this I/O request | ||
851 | */ | ||
852 | void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid); | ||
853 | |||
854 | /* | ||
825 | * ELS/CT interface | 855 | * ELS/CT interface |
826 | *****************************/ | 856 | *****************************/ |
827 | /* | 857 | /* |
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 941818f29f59..c41f7d0c6efc 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h | |||
@@ -124,24 +124,6 @@ static inline u16 skb_fc_rxid(const struct sk_buff *skb) | |||
124 | return be16_to_cpu(skb_fc_header(skb)->fh_rx_id); | 124 | return be16_to_cpu(skb_fc_header(skb)->fh_rx_id); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* FIXME - DMA_BIDIRECTIONAL ? */ | ||
128 | #define skb_cb(skb) ((struct fcoe_rcv_info *)&((skb)->cb[0])) | ||
129 | #define skb_cmd(skb) (skb_cb(skb)->fr_cmd) | ||
130 | #define skb_dir(skb) (skb_cmd(skb)->sc_data_direction) | ||
131 | static inline bool skb_fc_is_read(const struct sk_buff *skb) | ||
132 | { | ||
133 | if (skb_fc_is_cmd(skb) && skb_cmd(skb)) | ||
134 | return skb_dir(skb) == DMA_FROM_DEVICE; | ||
135 | return false; | ||
136 | } | ||
137 | |||
138 | static inline bool skb_fc_is_write(const struct sk_buff *skb) | ||
139 | { | ||
140 | if (skb_fc_is_cmd(skb) && skb_cmd(skb)) | ||
141 | return skb_dir(skb) == DMA_TO_DEVICE; | ||
142 | return false; | ||
143 | } | ||
144 | |||
145 | /* libfcoe funcs */ | 127 | /* libfcoe funcs */ |
146 | int fcoe_reset(struct Scsi_Host *shost); | 128 | int fcoe_reset(struct Scsi_Host *shost); |
147 | u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], | 129 | u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], |