Commit 5868287460b0fc243e828a0b856cd53d8bf45739
Committed by
James Bottomley
1 parent
07aac32834
Exists in
master
and in
7 other branches
[SCSI] libfc: Add routine to copy data from a buffer to a SG list
When handling the multi-frame responses of fc pass-thru requests, a code segment similar to fc_fcp_recv_data (routine to receive inbound SCSI data) is used in the response handler. This patch is to add a routine, called fc_copy_buffer_to_sglist(), to handle the common function of copying data from a buffer to a scatter- gather list in order to avoid code duplication. Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Showing 3 changed files with 78 additions and 46 deletions Side-by-side Diff
drivers/scsi/libfc/fc_fcp.c
... | ... | @@ -323,7 +323,7 @@ |
323 | 323 | size_t len; |
324 | 324 | void *buf; |
325 | 325 | struct scatterlist *sg; |
326 | - size_t remaining; | |
326 | + u32 nents; | |
327 | 327 | |
328 | 328 | fh = fc_frame_header_get(fp); |
329 | 329 | offset = ntohl(fh->fh_parm_offset); |
330 | 330 | |
331 | 331 | |
332 | 332 | |
333 | 333 | |
... | ... | @@ -347,55 +347,19 @@ |
347 | 347 | if (offset != fsp->xfer_len) |
348 | 348 | fsp->state |= FC_SRB_DISCONTIG; |
349 | 349 | |
350 | - crc = 0; | |
351 | - if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) | |
352 | - crc = crc32(~0, (u8 *) fh, sizeof(*fh)); | |
353 | - | |
354 | 350 | sg = scsi_sglist(sc); |
355 | - remaining = len; | |
351 | + nents = scsi_sg_count(sc); | |
356 | 352 | |
357 | - while (remaining > 0 && sg) { | |
358 | - size_t off; | |
359 | - void *page_addr; | |
360 | - size_t sg_bytes; | |
361 | - | |
362 | - if (offset >= sg->length) { | |
363 | - offset -= sg->length; | |
364 | - sg = sg_next(sg); | |
365 | - continue; | |
366 | - } | |
367 | - sg_bytes = min(remaining, sg->length - offset); | |
368 | - | |
369 | - /* | |
370 | - * The scatterlist item may be bigger than PAGE_SIZE, | |
371 | - * but we are limited to mapping PAGE_SIZE at a time. | |
372 | - */ | |
373 | - off = offset + sg->offset; | |
374 | - sg_bytes = min(sg_bytes, (size_t) | |
375 | - (PAGE_SIZE - (off & ~PAGE_MASK))); | |
376 | - page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT), | |
377 | - KM_SOFTIRQ0); | |
378 | - if (!page_addr) | |
379 | - break; /* XXX panic? */ | |
380 | - | |
381 | - if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) | |
382 | - crc = crc32(crc, buf, sg_bytes); | |
383 | - memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, | |
384 | - sg_bytes); | |
385 | - | |
386 | - kunmap_atomic(page_addr, KM_SOFTIRQ0); | |
387 | - buf += sg_bytes; | |
388 | - offset += sg_bytes; | |
389 | - remaining -= sg_bytes; | |
390 | - copy_len += sg_bytes; | |
391 | - } | |
392 | - | |
393 | - if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { | |
353 | + if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED)) { | |
354 | + copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents, | |
355 | + &offset, KM_SOFTIRQ0, NULL); | |
356 | + } else { | |
357 | + crc = crc32(~0, (u8 *) fh, sizeof(*fh)); | |
358 | + copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents, | |
359 | + &offset, KM_SOFTIRQ0, &crc); | |
394 | 360 | buf = fc_frame_payload_get(fp, 0); |
395 | - if (len % 4) { | |
361 | + if (len % 4) | |
396 | 362 | crc = crc32(crc, buf + len, 4 - (len % 4)); |
397 | - len += 4 - (len % 4); | |
398 | - } | |
399 | 363 | |
400 | 364 | if (~crc != le32_to_cpu(fr_crc(fp))) { |
401 | 365 | crc_err: |
drivers/scsi/libfc/fc_libfc.c
... | ... | @@ -72,4 +72,64 @@ |
72 | 72 | fc_destroy_rport(); |
73 | 73 | } |
74 | 74 | module_exit(libfc_exit); |
75 | + | |
76 | +/** | |
77 | + * fc_copy_buffer_to_sglist() - This routine copies the data of a buffer | |
78 | + * into a scatter-gather list (SG list). | |
79 | + * | |
80 | + * @buf: pointer to the data buffer. | |
81 | + * @len: the byte-length of the data buffer. | |
82 | + * @sg: pointer to the pointer of the SG list. | |
83 | + * @nents: pointer to the remaining number of entries in the SG list. | |
84 | + * @offset: pointer to the current offset in the SG list. | |
85 | + * @km_type: dedicated page table slot type for kmap_atomic. | |
86 | + * @crc: pointer to the 32-bit crc value. | |
87 | + * If crc is NULL, CRC is not calculated. | |
88 | + */ | |
89 | +u32 fc_copy_buffer_to_sglist(void *buf, size_t len, | |
90 | + struct scatterlist *sg, | |
91 | + u32 *nents, size_t *offset, | |
92 | + enum km_type km_type, u32 *crc) | |
93 | +{ | |
94 | + size_t remaining = len; | |
95 | + u32 copy_len = 0; | |
96 | + | |
97 | + while (remaining > 0 && sg) { | |
98 | + size_t off, sg_bytes; | |
99 | + void *page_addr; | |
100 | + | |
101 | + if (*offset >= sg->length) { | |
102 | + /* | |
103 | + * Check for end and drop resources | |
104 | + * from the last iteration. | |
105 | + */ | |
106 | + if (!(*nents)) | |
107 | + break; | |
108 | + --(*nents); | |
109 | + *offset -= sg->length; | |
110 | + sg = sg_next(sg); | |
111 | + continue; | |
112 | + } | |
113 | + sg_bytes = min(remaining, sg->length - *offset); | |
114 | + | |
115 | + /* | |
116 | + * The scatterlist item may be bigger than PAGE_SIZE, | |
117 | + * but we are limited to mapping PAGE_SIZE at a time. | |
118 | + */ | |
119 | + off = *offset + sg->offset; | |
120 | + sg_bytes = min(sg_bytes, | |
121 | + (size_t)(PAGE_SIZE - (off & ~PAGE_MASK))); | |
122 | + page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT), | |
123 | + km_type); | |
124 | + if (crc) | |
125 | + *crc = crc32(*crc, buf, sg_bytes); | |
126 | + memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes); | |
127 | + kunmap_atomic(page_addr, km_type); | |
128 | + buf += sg_bytes; | |
129 | + *offset += sg_bytes; | |
130 | + remaining -= sg_bytes; | |
131 | + copy_len += sg_bytes; | |
132 | + } | |
133 | + return copy_len; | |
134 | +} |
drivers/scsi/libfc/fc_libfc.h
... | ... | @@ -101,5 +101,13 @@ |
101 | 101 | */ |
102 | 102 | const char *fc_els_resp_type(struct fc_frame *); |
103 | 103 | |
104 | +/* | |
105 | + * Copies a buffer into an sg list | |
106 | + */ | |
107 | +u32 fc_copy_buffer_to_sglist(void *buf, size_t len, | |
108 | + struct scatterlist *sg, | |
109 | + u32 *nents, size_t *offset, | |
110 | + enum km_type km_type, u32 *crc); | |
111 | + | |
104 | 112 | #endif /* _FC_LIBFC_H_ */ |