aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/osd/osd_initiator.c148
-rw-r--r--include/scsi/osd_initiator.h9
-rw-r--r--include/scsi/osd_protocol.h42
-rw-r--r--include/scsi/osd_types.h5
4 files changed, 198 insertions, 6 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index acbdcb670ac5..f5b5735f76d5 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
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index a8f370126632..169a5dcda096 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -137,7 +137,7 @@ struct osd_request {
137 void *buff; 137 void *buff;
138 unsigned alloc_size; /* 0 here means: don't call kfree */ 138 unsigned alloc_size; /* 0 here means: don't call kfree */
139 unsigned total_bytes; 139 unsigned total_bytes;
140 } set_attr, enc_get_attr, get_attr; 140 } cdb_cont, set_attr, enc_get_attr, get_attr;
141 141
142 struct _osd_io_info { 142 struct _osd_io_info {
143 struct bio *bio; 143 struct bio *bio;
@@ -448,6 +448,13 @@ void osd_req_read(struct osd_request *or,
448int osd_req_read_kern(struct osd_request *or, 448int osd_req_read_kern(struct osd_request *or,
449 const struct osd_obj_id *obj, u64 offset, void *buff, u64 len); 449 const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
450 450
451/* Scatter/Gather write/read commands */
452int osd_req_write_sg(struct osd_request *or,
453 const struct osd_obj_id *obj, struct bio *bio,
454 const struct osd_sg_entry *sglist, unsigned numentries);
455int osd_req_read_sg(struct osd_request *or,
456 const struct osd_obj_id *obj, struct bio *bio,
457 const struct osd_sg_entry *sglist, unsigned numentries);
451/* 458/*
452 * Root/Partition/Collection/Object Attributes commands 459 * Root/Partition/Collection/Object Attributes commands
453 */ 460 */
diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h
index 685661283540..a6026da25f3e 100644
--- a/include/scsi/osd_protocol.h
+++ b/include/scsi/osd_protocol.h
@@ -631,4 +631,46 @@ static inline void osd_sec_set_caps(struct osd_capability_head *cap,
631 put_unaligned_le16(bit_mask, &cap->permissions_bit_mask); 631 put_unaligned_le16(bit_mask, &cap->permissions_bit_mask);
632} 632}
633 633
634/* osd2r05a sec 5.3: CDB continuation segment formats */
635enum osd_continuation_segment_format {
636 CDB_CONTINUATION_FORMAT_V2 = 0x01,
637};
638
639struct osd_continuation_segment_header {
640 u8 format;
641 u8 reserved1;
642 __be16 service_action;
643 __be32 reserved2;
644 u8 integrity_check[OSDv2_CRYPTO_KEYID_SIZE];
645} __packed;
646
647/* osd2r05a sec 5.4.1: CDB continuation descriptors */
648enum osd_continuation_descriptor_type {
649 NO_MORE_DESCRIPTORS = 0x0000,
650 SCATTER_GATHER_LIST = 0x0001,
651 QUERY_LIST = 0x0002,
652 USER_OBJECT = 0x0003,
653 COPY_USER_OBJECT_SOURCE = 0x0101,
654 EXTENSION_CAPABILITIES = 0xFFEE
655};
656
657struct osd_continuation_descriptor_header {
658 __be16 type;
659 u8 reserved;
660 u8 pad_length;
661 __be32 length;
662} __packed;
663
664
665/* osd2r05a sec 5.4.2: Scatter/gather list */
666struct osd_sg_list_entry {
667 __be64 offset;
668 __be64 len;
669};
670
671struct osd_sg_continuation_descriptor {
672 struct osd_continuation_descriptor_header hdr;
673 struct osd_sg_list_entry entries[];
674};
675
634#endif /* ndef __OSD_PROTOCOL_H__ */ 676#endif /* ndef __OSD_PROTOCOL_H__ */
diff --git a/include/scsi/osd_types.h b/include/scsi/osd_types.h
index 3f5e88cc75c0..bd0be7ed4bcf 100644
--- a/include/scsi/osd_types.h
+++ b/include/scsi/osd_types.h
@@ -37,4 +37,9 @@ struct osd_attr {
37 void *val_ptr; /* in network order */ 37 void *val_ptr; /* in network order */
38}; 38};
39 39
40struct osd_sg_entry {
41 u64 offset;
42 u64 len;
43};
44
40#endif /* ndef __OSD_TYPES_H__ */ 45#endif /* ndef __OSD_TYPES_H__ */