diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-02-22 21:23:33 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-06-02 15:42:19 -0400 |
commit | e6dc783a38ec0f2a5a91edda3f76195dffb17a16 (patch) | |
tree | 1e14032708ce350bbdc575dd07cbc20c7c8235d4 /drivers/scsi/virtio_scsi.c | |
parent | 95e7c4341b8e28dae5204378087c1e2a115abc82 (diff) |
virtio-scsi: Enable DIF/DIX modes in SCSI host LLD
This patch updates virtscsi_probe() to setup necessary Scsi_Host
level protection resources. (currently hardcoded to 1)
It changes virtscsi_add_cmd() to attach outgoing / incoming
protection SGLs preceeding the data payload, and is using the
new virtio_scsi_cmd_req_pi->pi_bytes[out,in] field to signal
to signal to vhost/scsi bytes to expect for protection data.
(Add missing #include <linux/blkdev.h> for blk_integrity - sfr + nab)
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Sagi Grimberg <sagig@dev.mellanox.co.il>
Cc: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/scsi/virtio_scsi.c')
-rw-r--r-- | drivers/scsi/virtio_scsi.c | 87 |
1 files changed, 69 insertions, 18 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 16bfd50cd3fe..1c326b63ca55 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/virtio_config.h> | 23 | #include <linux/virtio_config.h> |
24 | #include <linux/virtio_scsi.h> | 24 | #include <linux/virtio_scsi.h> |
25 | #include <linux/cpu.h> | 25 | #include <linux/cpu.h> |
26 | #include <linux/blkdev.h> | ||
26 | #include <scsi/scsi_host.h> | 27 | #include <scsi/scsi_host.h> |
27 | #include <scsi/scsi_device.h> | 28 | #include <scsi/scsi_device.h> |
28 | #include <scsi/scsi_cmnd.h> | 29 | #include <scsi/scsi_cmnd.h> |
@@ -37,6 +38,7 @@ struct virtio_scsi_cmd { | |||
37 | struct completion *comp; | 38 | struct completion *comp; |
38 | union { | 39 | union { |
39 | struct virtio_scsi_cmd_req cmd; | 40 | struct virtio_scsi_cmd_req cmd; |
41 | struct virtio_scsi_cmd_req_pi cmd_pi; | ||
40 | struct virtio_scsi_ctrl_tmf_req tmf; | 42 | struct virtio_scsi_ctrl_tmf_req tmf; |
41 | struct virtio_scsi_ctrl_an_req an; | 43 | struct virtio_scsi_ctrl_an_req an; |
42 | } req; | 44 | } req; |
@@ -440,7 +442,7 @@ static int virtscsi_add_cmd(struct virtqueue *vq, | |||
440 | size_t req_size, size_t resp_size, gfp_t gfp) | 442 | size_t req_size, size_t resp_size, gfp_t gfp) |
441 | { | 443 | { |
442 | struct scsi_cmnd *sc = cmd->sc; | 444 | struct scsi_cmnd *sc = cmd->sc; |
443 | struct scatterlist *sgs[4], req, resp; | 445 | struct scatterlist *sgs[6], req, resp; |
444 | struct sg_table *out, *in; | 446 | struct sg_table *out, *in; |
445 | unsigned out_num = 0, in_num = 0; | 447 | unsigned out_num = 0, in_num = 0; |
446 | 448 | ||
@@ -458,16 +460,24 @@ static int virtscsi_add_cmd(struct virtqueue *vq, | |||
458 | sgs[out_num++] = &req; | 460 | sgs[out_num++] = &req; |
459 | 461 | ||
460 | /* Data-out buffer. */ | 462 | /* Data-out buffer. */ |
461 | if (out) | 463 | if (out) { |
464 | /* Place WRITE protection SGLs before Data OUT payload */ | ||
465 | if (scsi_prot_sg_count(sc)) | ||
466 | sgs[out_num++] = scsi_prot_sglist(sc); | ||
462 | sgs[out_num++] = out->sgl; | 467 | sgs[out_num++] = out->sgl; |
468 | } | ||
463 | 469 | ||
464 | /* Response header. */ | 470 | /* Response header. */ |
465 | sg_init_one(&resp, &cmd->resp, resp_size); | 471 | sg_init_one(&resp, &cmd->resp, resp_size); |
466 | sgs[out_num + in_num++] = &resp; | 472 | sgs[out_num + in_num++] = &resp; |
467 | 473 | ||
468 | /* Data-in buffer */ | 474 | /* Data-in buffer */ |
469 | if (in) | 475 | if (in) { |
476 | /* Place READ protection SGLs before Data IN payload */ | ||
477 | if (scsi_prot_sg_count(sc)) | ||
478 | sgs[out_num + in_num++] = scsi_prot_sglist(sc); | ||
470 | sgs[out_num + in_num++] = in->sgl; | 479 | sgs[out_num + in_num++] = in->sgl; |
480 | } | ||
471 | 481 | ||
472 | return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, gfp); | 482 | return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, gfp); |
473 | } | 483 | } |
@@ -492,12 +502,44 @@ static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq, | |||
492 | return err; | 502 | return err; |
493 | } | 503 | } |
494 | 504 | ||
505 | static void virtio_scsi_init_hdr(struct virtio_scsi_cmd_req *cmd, | ||
506 | struct scsi_cmnd *sc) | ||
507 | { | ||
508 | cmd->lun[0] = 1; | ||
509 | cmd->lun[1] = sc->device->id; | ||
510 | cmd->lun[2] = (sc->device->lun >> 8) | 0x40; | ||
511 | cmd->lun[3] = sc->device->lun & 0xff; | ||
512 | cmd->tag = (unsigned long)sc; | ||
513 | cmd->task_attr = VIRTIO_SCSI_S_SIMPLE; | ||
514 | cmd->prio = 0; | ||
515 | cmd->crn = 0; | ||
516 | } | ||
517 | |||
518 | static void virtio_scsi_init_hdr_pi(struct virtio_scsi_cmd_req_pi *cmd_pi, | ||
519 | struct scsi_cmnd *sc) | ||
520 | { | ||
521 | struct request *rq = sc->request; | ||
522 | struct blk_integrity *bi; | ||
523 | |||
524 | virtio_scsi_init_hdr((struct virtio_scsi_cmd_req *)cmd_pi, sc); | ||
525 | |||
526 | if (!rq || !scsi_prot_sg_count(sc)) | ||
527 | return; | ||
528 | |||
529 | bi = blk_get_integrity(rq->rq_disk); | ||
530 | |||
531 | if (sc->sc_data_direction == DMA_TO_DEVICE) | ||
532 | cmd_pi->pi_bytesout = blk_rq_sectors(rq) * bi->tuple_size; | ||
533 | else if (sc->sc_data_direction == DMA_FROM_DEVICE) | ||
534 | cmd_pi->pi_bytesin = blk_rq_sectors(rq) * bi->tuple_size; | ||
535 | } | ||
536 | |||
495 | static int virtscsi_queuecommand(struct virtio_scsi *vscsi, | 537 | static int virtscsi_queuecommand(struct virtio_scsi *vscsi, |
496 | struct virtio_scsi_vq *req_vq, | 538 | struct virtio_scsi_vq *req_vq, |
497 | struct scsi_cmnd *sc) | 539 | struct scsi_cmnd *sc) |
498 | { | 540 | { |
499 | struct virtio_scsi_cmd *cmd; | 541 | struct virtio_scsi_cmd *cmd; |
500 | int ret; | 542 | int ret, req_size; |
501 | 543 | ||
502 | struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); | 544 | struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); |
503 | BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); | 545 | BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); |
@@ -515,22 +557,20 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi, | |||
515 | 557 | ||
516 | memset(cmd, 0, sizeof(*cmd)); | 558 | memset(cmd, 0, sizeof(*cmd)); |
517 | cmd->sc = sc; | 559 | cmd->sc = sc; |
518 | cmd->req.cmd = (struct virtio_scsi_cmd_req){ | ||
519 | .lun[0] = 1, | ||
520 | .lun[1] = sc->device->id, | ||
521 | .lun[2] = (sc->device->lun >> 8) | 0x40, | ||
522 | .lun[3] = sc->device->lun & 0xff, | ||
523 | .tag = (unsigned long)sc, | ||
524 | .task_attr = VIRTIO_SCSI_S_SIMPLE, | ||
525 | .prio = 0, | ||
526 | .crn = 0, | ||
527 | }; | ||
528 | 560 | ||
529 | BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); | 561 | BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); |
530 | memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); | ||
531 | 562 | ||
532 | if (virtscsi_kick_cmd(req_vq, cmd, | 563 | if (virtio_has_feature(vscsi->vdev, VIRTIO_SCSI_F_T10_PI)) { |
533 | sizeof cmd->req.cmd, sizeof cmd->resp.cmd, | 564 | virtio_scsi_init_hdr_pi(&cmd->req.cmd_pi, sc); |
565 | memcpy(cmd->req.cmd_pi.cdb, sc->cmnd, sc->cmd_len); | ||
566 | req_size = sizeof(cmd->req.cmd_pi); | ||
567 | } else { | ||
568 | virtio_scsi_init_hdr(&cmd->req.cmd, sc); | ||
569 | memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); | ||
570 | req_size = sizeof(cmd->req.cmd); | ||
571 | } | ||
572 | |||
573 | if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd), | ||
534 | GFP_ATOMIC) == 0) | 574 | GFP_ATOMIC) == 0) |
535 | ret = 0; | 575 | ret = 0; |
536 | else | 576 | else |
@@ -871,7 +911,7 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
871 | { | 911 | { |
872 | struct Scsi_Host *shost; | 912 | struct Scsi_Host *shost; |
873 | struct virtio_scsi *vscsi; | 913 | struct virtio_scsi *vscsi; |
874 | int err; | 914 | int err, host_prot; |
875 | u32 sg_elems, num_targets; | 915 | u32 sg_elems, num_targets; |
876 | u32 cmd_per_lun; | 916 | u32 cmd_per_lun; |
877 | u32 num_queues; | 917 | u32 num_queues; |
@@ -921,6 +961,16 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
921 | shost->max_id = num_targets; | 961 | shost->max_id = num_targets; |
922 | shost->max_channel = 0; | 962 | shost->max_channel = 0; |
923 | shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; | 963 | shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; |
964 | |||
965 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_T10_PI)) { | ||
966 | host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | | ||
967 | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION | | ||
968 | SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION; | ||
969 | |||
970 | scsi_host_set_prot(shost, host_prot); | ||
971 | scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); | ||
972 | } | ||
973 | |||
924 | err = scsi_add_host(shost, &vdev->dev); | 974 | err = scsi_add_host(shost, &vdev->dev); |
925 | if (err) | 975 | if (err) |
926 | goto scsi_add_host_failed; | 976 | goto scsi_add_host_failed; |
@@ -990,6 +1040,7 @@ static struct virtio_device_id id_table[] = { | |||
990 | static unsigned int features[] = { | 1040 | static unsigned int features[] = { |
991 | VIRTIO_SCSI_F_HOTPLUG, | 1041 | VIRTIO_SCSI_F_HOTPLUG, |
992 | VIRTIO_SCSI_F_CHANGE, | 1042 | VIRTIO_SCSI_F_CHANGE, |
1043 | VIRTIO_SCSI_F_T10_PI, | ||
993 | }; | 1044 | }; |
994 | 1045 | ||
995 | static struct virtio_driver virtio_scsi_driver = { | 1046 | static struct virtio_driver virtio_scsi_driver = { |