aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/osd/osd_initiator.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/osd/osd_initiator.c')
-rw-r--r--drivers/scsi/osd/osd_initiator.c244
1 files changed, 229 insertions, 15 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index e88bbdde49c5..0433ea6f27c9 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -452,10 +452,6 @@ void osd_end_request(struct osd_request *or)
452{ 452{
453 struct request *rq = or->request; 453 struct request *rq = or->request;
454 454
455 _osd_free_seg(or, &or->set_attr);
456 _osd_free_seg(or, &or->enc_get_attr);
457 _osd_free_seg(or, &or->get_attr);
458
459 if (rq) { 455 if (rq) {
460 if (rq->next_rq) { 456 if (rq->next_rq) {
461 _put_request(rq->next_rq); 457 _put_request(rq->next_rq);
@@ -464,6 +460,12 @@ void osd_end_request(struct osd_request *or)
464 460
465 _put_request(rq); 461 _put_request(rq);
466 } 462 }
463
464 _osd_free_seg(or, &or->get_attr);
465 _osd_free_seg(or, &or->enc_get_attr);
466 _osd_free_seg(or, &or->set_attr);
467 _osd_free_seg(or, &or->cdb_cont);
468
467 _osd_request_free(or); 469 _osd_request_free(or);
468} 470}
469EXPORT_SYMBOL(osd_end_request); 471EXPORT_SYMBOL(osd_end_request);
@@ -547,6 +549,12 @@ static int _osd_realloc_seg(struct osd_request *or,
547 return 0; 549 return 0;
548} 550}
549 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
550static int _alloc_set_attr_list(struct osd_request *or, 558static int _alloc_set_attr_list(struct osd_request *or,
551 const struct osd_attr *oa, unsigned nelem, unsigned add_bytes) 559 const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
552{ 560{
@@ -885,6 +893,199 @@ int osd_req_read_kern(struct osd_request *or,
885} 893}
886EXPORT_SYMBOL(osd_req_read_kern); 894EXPORT_SYMBOL(osd_req_read_kern);
887 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
1018/* SG-list write/read Kern API
1019 *
1020 * osd_req_{write,read}_sg_kern takes an array of @buff pointers and an array
1021 * of sg_entries. @numentries indicates how many pointers and sg_entries there
1022 * are. By requiring an array of buff pointers. This allows a caller to do a
1023 * single write/read and scatter into multiple buffers.
1024 * NOTE: Each buffer + len should not cross a page boundary.
1025 */
1026static struct bio *_create_sg_bios(struct osd_request *or,
1027 void **buff, const struct osd_sg_entry *sglist, unsigned numentries)
1028{
1029 struct request_queue *q = osd_request_queue(or->osd_dev);
1030 struct bio *bio;
1031 unsigned i;
1032
1033 bio = bio_kmalloc(GFP_KERNEL, numentries);
1034 if (unlikely(!bio)) {
1035 OSD_DEBUG("Faild to allocate BIO size=%u\n", numentries);
1036 return ERR_PTR(-ENOMEM);
1037 }
1038
1039 for (i = 0; i < numentries; i++) {
1040 unsigned offset = offset_in_page(buff[i]);
1041 struct page *page = virt_to_page(buff[i]);
1042 unsigned len = sglist[i].len;
1043 unsigned added_len;
1044
1045 BUG_ON(offset + len > PAGE_SIZE);
1046 added_len = bio_add_pc_page(q, bio, page, len, offset);
1047 if (unlikely(len != added_len)) {
1048 OSD_DEBUG("bio_add_pc_page len(%d) != added_len(%d)\n",
1049 len, added_len);
1050 bio_put(bio);
1051 return ERR_PTR(-ENOMEM);
1052 }
1053 }
1054
1055 return bio;
1056}
1057
1058int osd_req_write_sg_kern(struct osd_request *or,
1059 const struct osd_obj_id *obj, void **buff,
1060 const struct osd_sg_entry *sglist, unsigned numentries)
1061{
1062 struct bio *bio = _create_sg_bios(or, buff, sglist, numentries);
1063 if (IS_ERR(bio))
1064 return PTR_ERR(bio);
1065
1066 bio->bi_rw |= REQ_WRITE;
1067 osd_req_write_sg(or, obj, bio, sglist, numentries);
1068
1069 return 0;
1070}
1071EXPORT_SYMBOL(osd_req_write_sg_kern);
1072
1073int osd_req_read_sg_kern(struct osd_request *or,
1074 const struct osd_obj_id *obj, void **buff,
1075 const struct osd_sg_entry *sglist, unsigned numentries)
1076{
1077 struct bio *bio = _create_sg_bios(or, buff, sglist, numentries);
1078 if (IS_ERR(bio))
1079 return PTR_ERR(bio);
1080
1081 osd_req_read_sg(or, obj, bio, sglist, numentries);
1082
1083 return 0;
1084}
1085EXPORT_SYMBOL(osd_req_read_sg_kern);
1086
1087
1088
888void osd_req_get_attributes(struct osd_request *or, 1089void osd_req_get_attributes(struct osd_request *or,
889 const struct osd_obj_id *obj) 1090 const struct osd_obj_id *obj)
890{ 1091{
@@ -1218,17 +1419,18 @@ int osd_req_add_get_attr_page(struct osd_request *or,
1218 or->get_attr.buff = attar_page; 1419 or->get_attr.buff = attar_page;
1219 or->get_attr.total_bytes = max_page_len; 1420 or->get_attr.total_bytes = max_page_len;
1220 1421
1221 or->set_attr.buff = set_one_attr->val_ptr;
1222 or->set_attr.total_bytes = set_one_attr->len;
1223
1224 cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id); 1422 cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
1225 cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len); 1423 cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
1226 /* ocdb->attrs_page.get_attr_offset; */ 1424
1425 if (!set_one_attr || !set_one_attr->attr_page)
1426 return 0; /* The set is optional */
1427
1428 or->set_attr.buff = set_one_attr->val_ptr;
1429 or->set_attr.total_bytes = set_one_attr->len;
1227 1430
1228 cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page); 1431 cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
1229 cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id); 1432 cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
1230 cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len); 1433 cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
1231 /* ocdb->attrs_page.set_attr_offset; */
1232 return 0; 1434 return 0;
1233} 1435}
1234EXPORT_SYMBOL(osd_req_add_get_attr_page); 1436EXPORT_SYMBOL(osd_req_add_get_attr_page);
@@ -1248,11 +1450,14 @@ static int _osd_req_finalize_attr_page(struct osd_request *or)
1248 if (ret) 1450 if (ret)
1249 return ret; 1451 return ret;
1250 1452
1453 if (or->set_attr.total_bytes == 0)
1454 return 0;
1455
1251 /* set one value */ 1456 /* set one value */
1252 cdbh->attrs_page.set_attr_offset = 1457 cdbh->attrs_page.set_attr_offset =
1253 osd_req_encode_offset(or, or->out.total_bytes, &out_padding); 1458 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
1254 1459
1255 ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL, 1460 ret = _req_append_segment(or, out_padding, &or->set_attr, NULL,
1256 &or->out); 1461 &or->out);
1257 return ret; 1462 return ret;
1258} 1463}
@@ -1276,7 +1481,8 @@ static inline void osd_sec_parms_set_in_offset(bool is_v1,
1276} 1481}
1277 1482
1278static int _osd_req_finalize_data_integrity(struct osd_request *or, 1483static int _osd_req_finalize_data_integrity(struct osd_request *or,
1279 bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key) 1484 bool has_in, bool has_out, struct bio *out_data_bio, u64 out_data_bytes,
1485 const u8 *cap_key)
1280{ 1486{
1281 struct osd_security_parameters *sec_parms = _osd_req_sec_params(or); 1487 struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
1282 int ret; 1488 int ret;
@@ -1307,7 +1513,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
1307 or->out.last_seg = NULL; 1513 or->out.last_seg = NULL;
1308 1514
1309 /* they are now all chained to request sign them all together */ 1515 /* they are now all chained to request sign them all together */
1310 osd_sec_sign_data(&or->out_data_integ, or->out.req->bio, 1516 osd_sec_sign_data(&or->out_data_integ, out_data_bio,
1311 cap_key); 1517 cap_key);
1312 } 1518 }
1313 1519
@@ -1403,6 +1609,8 @@ int osd_finalize_request(struct osd_request *or,
1403{ 1609{
1404 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); 1610 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1405 bool has_in, has_out; 1611 bool has_in, has_out;
1612 /* Save for data_integrity without the cdb_continuation */
1613 struct bio *out_data_bio = or->out.bio;
1406 u64 out_data_bytes = or->out.total_bytes; 1614 u64 out_data_bytes = or->out.total_bytes;
1407 int ret; 1615 int ret;
1408 1616
@@ -1418,9 +1626,14 @@ int osd_finalize_request(struct osd_request *or,
1418 osd_set_caps(&or->cdb, cap); 1626 osd_set_caps(&or->cdb, cap);
1419 1627
1420 has_in = or->in.bio || or->get_attr.total_bytes; 1628 has_in = or->in.bio || or->get_attr.total_bytes;
1421 has_out = or->out.bio || or->set_attr.total_bytes || 1629 has_out = or->out.bio || or->cdb_cont.total_bytes ||
1422 or->enc_get_attr.total_bytes; 1630 or->set_attr.total_bytes || or->enc_get_attr.total_bytes;
1423 1631
1632 ret = _osd_req_finalize_cdb_cont(or, cap_key);
1633 if (ret) {
1634 OSD_DEBUG("_osd_req_finalize_cdb_cont failed\n");
1635 return ret;
1636 }
1424 ret = _init_blk_request(or, has_in, has_out); 1637 ret = _init_blk_request(or, has_in, has_out);
1425 if (ret) { 1638 if (ret) {
1426 OSD_DEBUG("_init_blk_request failed\n"); 1639 OSD_DEBUG("_init_blk_request failed\n");
@@ -1458,7 +1671,8 @@ int osd_finalize_request(struct osd_request *or,
1458 } 1671 }
1459 1672
1460 ret = _osd_req_finalize_data_integrity(or, has_in, has_out, 1673 ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
1461 out_data_bytes, cap_key); 1674 out_data_bio, out_data_bytes,
1675 cap_key);
1462 if (ret) 1676 if (ret)
1463 return ret; 1677 return ret;
1464 1678