aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/osd/osd_initiator.c148
1 files changed, 143 insertions, 5 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index acbdcb670ac..f5b5735f76d 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -464,6 +464,7 @@ void osd_end_request(struct osd_request *or)
464 _osd_free_seg(or, &or->get_attr); 464 _osd_free_seg(or, &or->get_attr);
465 _osd_free_seg(or, &or->enc_get_attr); 465 _osd_free_seg(or, &or->enc_get_attr);
466 _osd_free_seg(or, &or->set_attr); 466 _osd_free_seg(or, &or->set_attr);
467 _osd_free_seg(or, &or->cdb_cont);
467 468
468 _osd_request_free(or); 469 _osd_request_free(or);
469} 470}
@@ -548,6 +549,12 @@ static int _osd_realloc_seg(struct osd_request *or,
548 return 0; 549 return 0;
549} 550}
550 551
552static int _alloc_cdb_cont(struct osd_request *or, unsigned total_bytes)
553{
554 OSD_DEBUG("total_bytes=%d\n", total_bytes);
555 return _osd_realloc_seg(or, &or->cdb_cont, total_bytes);
556}
557
551static int _alloc_set_attr_list(struct osd_request *or, 558static int _alloc_set_attr_list(struct osd_request *or,
552 const struct osd_attr *oa, unsigned nelem, unsigned add_bytes) 559 const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
553{ 560{
@@ -886,6 +893,128 @@ int osd_req_read_kern(struct osd_request *or,
886} 893}
887EXPORT_SYMBOL(osd_req_read_kern); 894EXPORT_SYMBOL(osd_req_read_kern);
888 895
896static int _add_sg_continuation_descriptor(struct osd_request *or,
897 const struct osd_sg_entry *sglist, unsigned numentries, u64 *len)
898{
899 struct osd_sg_continuation_descriptor *oscd;
900 u32 oscd_size;
901 unsigned i;
902 int ret;
903
904 oscd_size = sizeof(*oscd) + numentries * sizeof(oscd->entries[0]);
905
906 if (!or->cdb_cont.total_bytes) {
907 /* First time, jump over the header, we will write to:
908 * cdb_cont.buff + cdb_cont.total_bytes
909 */
910 or->cdb_cont.total_bytes =
911 sizeof(struct osd_continuation_segment_header);
912 }
913
914 ret = _alloc_cdb_cont(or, or->cdb_cont.total_bytes + oscd_size);
915 if (unlikely(ret))
916 return ret;
917
918 oscd = or->cdb_cont.buff + or->cdb_cont.total_bytes;
919 oscd->hdr.type = cpu_to_be16(SCATTER_GATHER_LIST);
920 oscd->hdr.pad_length = 0;
921 oscd->hdr.length = cpu_to_be32(oscd_size - sizeof(*oscd));
922
923 *len = 0;
924 /* copy the sg entries and convert to network byte order */
925 for (i = 0; i < numentries; i++) {
926 oscd->entries[i].offset = cpu_to_be64(sglist[i].offset);
927 oscd->entries[i].len = cpu_to_be64(sglist[i].len);
928 *len += sglist[i].len;
929 }
930
931 or->cdb_cont.total_bytes += oscd_size;
932 OSD_DEBUG("total_bytes=%d oscd_size=%d numentries=%d\n",
933 or->cdb_cont.total_bytes, oscd_size, numentries);
934 return 0;
935}
936
937static int _osd_req_finalize_cdb_cont(struct osd_request *or, const u8 *cap_key)
938{
939 struct request_queue *req_q = osd_request_queue(or->osd_dev);
940 struct bio *bio;
941 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
942 struct osd_continuation_segment_header *cont_seg_hdr;
943
944 if (!or->cdb_cont.total_bytes)
945 return 0;
946
947 cont_seg_hdr = or->cdb_cont.buff;
948 cont_seg_hdr->format = CDB_CONTINUATION_FORMAT_V2;
949 cont_seg_hdr->service_action = cdbh->varlen_cdb.service_action;
950
951 /* create a bio for continuation segment */
952 bio = bio_map_kern(req_q, or->cdb_cont.buff, or->cdb_cont.total_bytes,
953 GFP_KERNEL);
954 if (unlikely(!bio))
955 return -ENOMEM;
956
957 bio->bi_rw |= REQ_WRITE;
958
959 /* integrity check the continuation before the bio is linked
960 * with the other data segments since the continuation
961 * integrity is separate from the other data segments.
962 */
963 osd_sec_sign_data(cont_seg_hdr->integrity_check, bio, cap_key);
964
965 cdbh->v2.cdb_continuation_length = cpu_to_be32(or->cdb_cont.total_bytes);
966
967 /* we can't use _req_append_segment, because we need to link in the
968 * continuation bio to the head of the bio list - the
969 * continuation segment (if it exists) is always the first segment in
970 * the out data buffer.
971 */
972 bio->bi_next = or->out.bio;
973 or->out.bio = bio;
974 or->out.total_bytes += or->cdb_cont.total_bytes;
975
976 return 0;
977}
978
979/* osd_req_write_sg: Takes a @bio that points to the data out buffer and an
980 * @sglist that has the scatter gather entries. Scatter-gather enables a write
981 * of multiple none-contiguous areas of an object, in a single call. The extents
982 * may overlap and/or be in any order. The only constrain is that:
983 * total_bytes(sglist) >= total_bytes(bio)
984 */
985int osd_req_write_sg(struct osd_request *or,
986 const struct osd_obj_id *obj, struct bio *bio,
987 const struct osd_sg_entry *sglist, unsigned numentries)
988{
989 u64 len;
990 int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len);
991
992 if (ret)
993 return ret;
994 osd_req_write(or, obj, 0, bio, len);
995
996 return 0;
997}
998EXPORT_SYMBOL(osd_req_write_sg);
999
1000/* osd_req_read_sg: Read multiple extents of an object into @bio
1001 * See osd_req_write_sg
1002 */
1003int osd_req_read_sg(struct osd_request *or,
1004 const struct osd_obj_id *obj, struct bio *bio,
1005 const struct osd_sg_entry *sglist, unsigned numentries)
1006{
1007 u64 len;
1008 int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len);
1009
1010 if (ret)
1011 return ret;
1012 osd_req_read(or, obj, 0, bio, len);
1013
1014 return 0;
1015}
1016EXPORT_SYMBOL(osd_req_read_sg);
1017
889void osd_req_get_attributes(struct osd_request *or, 1018void osd_req_get_attributes(struct osd_request *or,
890 const struct osd_obj_id *obj) 1019 const struct osd_obj_id *obj)
891{ 1020{
@@ -1281,7 +1410,8 @@ static inline void osd_sec_parms_set_in_offset(bool is_v1,
1281} 1410}
1282 1411
1283static int _osd_req_finalize_data_integrity(struct osd_request *or, 1412static int _osd_req_finalize_data_integrity(struct osd_request *or,
1284 bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key) 1413 bool has_in, bool has_out, struct bio *out_data_bio, u64 out_data_bytes,
1414 const u8 *cap_key)
1285{ 1415{
1286 struct osd_security_parameters *sec_parms = _osd_req_sec_params(or); 1416 struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
1287 int ret; 1417 int ret;
@@ -1312,7 +1442,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
1312 or->out.last_seg = NULL; 1442 or->out.last_seg = NULL;
1313 1443
1314 /* they are now all chained to request sign them all together */ 1444 /* they are now all chained to request sign them all together */
1315 osd_sec_sign_data(&or->out_data_integ, or->out.req->bio, 1445 osd_sec_sign_data(&or->out_data_integ, out_data_bio,
1316 cap_key); 1446 cap_key);
1317 } 1447 }
1318 1448
@@ -1408,6 +1538,8 @@ int osd_finalize_request(struct osd_request *or,
1408{ 1538{
1409 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); 1539 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1410 bool has_in, has_out; 1540 bool has_in, has_out;
1541 /* Save for data_integrity without the cdb_continuation */
1542 struct bio *out_data_bio = or->out.bio;
1411 u64 out_data_bytes = or->out.total_bytes; 1543 u64 out_data_bytes = or->out.total_bytes;
1412 int ret; 1544 int ret;
1413 1545
@@ -1423,9 +1555,14 @@ int osd_finalize_request(struct osd_request *or,
1423 osd_set_caps(&or->cdb, cap); 1555 osd_set_caps(&or->cdb, cap);
1424 1556
1425 has_in = or->in.bio || or->get_attr.total_bytes; 1557 has_in = or->in.bio || or->get_attr.total_bytes;
1426 has_out = or->out.bio || or->set_attr.total_bytes || 1558 has_out = or->out.bio || or->cdb_cont.total_bytes ||
1427 or->enc_get_attr.total_bytes; 1559 or->set_attr.total_bytes || or->enc_get_attr.total_bytes;
1428 1560
1561 ret = _osd_req_finalize_cdb_cont(or, cap_key);
1562 if (ret) {
1563 OSD_DEBUG("_osd_req_finalize_cdb_cont failed\n");
1564 return ret;
1565 }
1429 ret = _init_blk_request(or, has_in, has_out); 1566 ret = _init_blk_request(or, has_in, has_out);
1430 if (ret) { 1567 if (ret) {
1431 OSD_DEBUG("_init_blk_request failed\n"); 1568 OSD_DEBUG("_init_blk_request failed\n");
@@ -1463,7 +1600,8 @@ int osd_finalize_request(struct osd_request *or,
1463 } 1600 }
1464 1601
1465 ret = _osd_req_finalize_data_integrity(or, has_in, has_out, 1602 ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
1466 out_data_bytes, cap_key); 1603 out_data_bio, out_data_bytes,
1604 cap_key);
1467 if (ret) 1605 if (ret)
1468 return ret; 1606 return ret;
1469 1607