diff options
Diffstat (limited to 'drivers/scsi/virtio_scsi.c')
| -rw-r--r-- | drivers/scsi/virtio_scsi.c | 86 |
1 files changed, 69 insertions, 17 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 99fdb9403944..89ee5929eb6d 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; |
| @@ -399,7 +401,7 @@ static int virtscsi_add_cmd(struct virtqueue *vq, | |||
| 399 | size_t req_size, size_t resp_size) | 401 | size_t req_size, size_t resp_size) |
| 400 | { | 402 | { |
| 401 | struct scsi_cmnd *sc = cmd->sc; | 403 | struct scsi_cmnd *sc = cmd->sc; |
| 402 | struct scatterlist *sgs[4], req, resp; | 404 | struct scatterlist *sgs[6], req, resp; |
| 403 | struct sg_table *out, *in; | 405 | struct sg_table *out, *in; |
| 404 | unsigned out_num = 0, in_num = 0; | 406 | unsigned out_num = 0, in_num = 0; |
| 405 | 407 | ||
| @@ -417,16 +419,24 @@ static int virtscsi_add_cmd(struct virtqueue *vq, | |||
| 417 | sgs[out_num++] = &req; | 419 | sgs[out_num++] = &req; |
| 418 | 420 | ||
| 419 | /* Data-out buffer. */ | 421 | /* Data-out buffer. */ |
| 420 | if (out) | 422 | if (out) { |
| 423 | /* Place WRITE protection SGLs before Data OUT payload */ | ||
| 424 | if (scsi_prot_sg_count(sc)) | ||
| 425 | sgs[out_num++] = scsi_prot_sglist(sc); | ||
| 421 | sgs[out_num++] = out->sgl; | 426 | sgs[out_num++] = out->sgl; |
| 427 | } | ||
| 422 | 428 | ||
| 423 | /* Response header. */ | 429 | /* Response header. */ |
| 424 | sg_init_one(&resp, &cmd->resp, resp_size); | 430 | sg_init_one(&resp, &cmd->resp, resp_size); |
| 425 | sgs[out_num + in_num++] = &resp; | 431 | sgs[out_num + in_num++] = &resp; |
| 426 | 432 | ||
| 427 | /* Data-in buffer */ | 433 | /* Data-in buffer */ |
| 428 | if (in) | 434 | if (in) { |
| 435 | /* Place READ protection SGLs before Data IN payload */ | ||
| 436 | if (scsi_prot_sg_count(sc)) | ||
| 437 | sgs[out_num + in_num++] = scsi_prot_sglist(sc); | ||
| 429 | sgs[out_num + in_num++] = in->sgl; | 438 | sgs[out_num + in_num++] = in->sgl; |
| 439 | } | ||
| 430 | 440 | ||
| 431 | return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC); | 441 | return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC); |
| 432 | } | 442 | } |
| @@ -451,12 +461,45 @@ static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq, | |||
| 451 | return err; | 461 | return err; |
| 452 | } | 462 | } |
| 453 | 463 | ||
| 464 | static void virtio_scsi_init_hdr(struct virtio_scsi_cmd_req *cmd, | ||
| 465 | struct scsi_cmnd *sc) | ||
| 466 | { | ||
| 467 | cmd->lun[0] = 1; | ||
| 468 | cmd->lun[1] = sc->device->id; | ||
| 469 | cmd->lun[2] = (sc->device->lun >> 8) | 0x40; | ||
| 470 | cmd->lun[3] = sc->device->lun & 0xff; | ||
| 471 | cmd->tag = (unsigned long)sc; | ||
| 472 | cmd->task_attr = VIRTIO_SCSI_S_SIMPLE; | ||
| 473 | cmd->prio = 0; | ||
| 474 | cmd->crn = 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void virtio_scsi_init_hdr_pi(struct virtio_scsi_cmd_req_pi *cmd_pi, | ||
| 478 | struct scsi_cmnd *sc) | ||
| 479 | { | ||
| 480 | struct request *rq = sc->request; | ||
| 481 | struct blk_integrity *bi; | ||
| 482 | |||
| 483 | virtio_scsi_init_hdr((struct virtio_scsi_cmd_req *)cmd_pi, sc); | ||
| 484 | |||
| 485 | if (!rq || !scsi_prot_sg_count(sc)) | ||
| 486 | return; | ||
| 487 | |||
| 488 | bi = blk_get_integrity(rq->rq_disk); | ||
| 489 | |||
| 490 | if (sc->sc_data_direction == DMA_TO_DEVICE) | ||
| 491 | cmd_pi->pi_bytesout = blk_rq_sectors(rq) * bi->tuple_size; | ||
| 492 | else if (sc->sc_data_direction == DMA_FROM_DEVICE) | ||
| 493 | cmd_pi->pi_bytesin = blk_rq_sectors(rq) * bi->tuple_size; | ||
| 494 | } | ||
| 495 | |||
| 454 | static int virtscsi_queuecommand(struct virtio_scsi *vscsi, | 496 | static int virtscsi_queuecommand(struct virtio_scsi *vscsi, |
| 455 | struct virtio_scsi_vq *req_vq, | 497 | struct virtio_scsi_vq *req_vq, |
| 456 | struct scsi_cmnd *sc) | 498 | struct scsi_cmnd *sc) |
| 457 | { | 499 | { |
| 458 | struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); | 500 | struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); |
| 459 | struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); | 501 | struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); |
| 502 | int req_size; | ||
| 460 | 503 | ||
| 461 | BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); | 504 | BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); |
| 462 | 505 | ||
| @@ -468,22 +511,20 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi, | |||
| 468 | 511 | ||
| 469 | memset(cmd, 0, sizeof(*cmd)); | 512 | memset(cmd, 0, sizeof(*cmd)); |
| 470 | cmd->sc = sc; | 513 | cmd->sc = sc; |
| 471 | cmd->req.cmd = (struct virtio_scsi_cmd_req){ | ||
| 472 | .lun[0] = 1, | ||
| 473 | .lun[1] = sc->device->id, | ||
| 474 | .lun[2] = (sc->device->lun >> 8) | 0x40, | ||
| 475 | .lun[3] = sc->device->lun & 0xff, | ||
| 476 | .tag = (unsigned long)sc, | ||
| 477 | .task_attr = VIRTIO_SCSI_S_SIMPLE, | ||
| 478 | .prio = 0, | ||
| 479 | .crn = 0, | ||
| 480 | }; | ||
| 481 | 514 | ||
| 482 | BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); | 515 | BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); |
| 483 | memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); | ||
| 484 | 516 | ||
| 485 | if (virtscsi_kick_cmd(req_vq, cmd, | 517 | if (virtio_has_feature(vscsi->vdev, VIRTIO_SCSI_F_T10_PI)) { |
| 486 | sizeof cmd->req.cmd, sizeof cmd->resp.cmd) != 0) | 518 | virtio_scsi_init_hdr_pi(&cmd->req.cmd_pi, sc); |
| 519 | memcpy(cmd->req.cmd_pi.cdb, sc->cmnd, sc->cmd_len); | ||
| 520 | req_size = sizeof(cmd->req.cmd_pi); | ||
| 521 | } else { | ||
| 522 | virtio_scsi_init_hdr(&cmd->req.cmd, sc); | ||
| 523 | memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); | ||
| 524 | req_size = sizeof(cmd->req.cmd); | ||
| 525 | } | ||
| 526 | |||
| 527 | if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0) | ||
| 487 | return SCSI_MLQUEUE_HOST_BUSY; | 528 | return SCSI_MLQUEUE_HOST_BUSY; |
| 488 | return 0; | 529 | return 0; |
| 489 | } | 530 | } |
| @@ -820,7 +861,7 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
| 820 | { | 861 | { |
| 821 | struct Scsi_Host *shost; | 862 | struct Scsi_Host *shost; |
| 822 | struct virtio_scsi *vscsi; | 863 | struct virtio_scsi *vscsi; |
| 823 | int err; | 864 | int err, host_prot; |
| 824 | u32 sg_elems, num_targets; | 865 | u32 sg_elems, num_targets; |
| 825 | u32 cmd_per_lun; | 866 | u32 cmd_per_lun; |
| 826 | u32 num_queues; | 867 | u32 num_queues; |
| @@ -870,6 +911,16 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
| 870 | shost->max_id = num_targets; | 911 | shost->max_id = num_targets; |
| 871 | shost->max_channel = 0; | 912 | shost->max_channel = 0; |
| 872 | shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; | 913 | shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; |
| 914 | |||
| 915 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_T10_PI)) { | ||
| 916 | host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | | ||
| 917 | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION | | ||
| 918 | SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION; | ||
| 919 | |||
| 920 | scsi_host_set_prot(shost, host_prot); | ||
| 921 | scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); | ||
| 922 | } | ||
| 923 | |||
| 873 | err = scsi_add_host(shost, &vdev->dev); | 924 | err = scsi_add_host(shost, &vdev->dev); |
| 874 | if (err) | 925 | if (err) |
| 875 | goto scsi_add_host_failed; | 926 | goto scsi_add_host_failed; |
| @@ -939,6 +990,7 @@ static struct virtio_device_id id_table[] = { | |||
| 939 | static unsigned int features[] = { | 990 | static unsigned int features[] = { |
| 940 | VIRTIO_SCSI_F_HOTPLUG, | 991 | VIRTIO_SCSI_F_HOTPLUG, |
| 941 | VIRTIO_SCSI_F_CHANGE, | 992 | VIRTIO_SCSI_F_CHANGE, |
| 993 | VIRTIO_SCSI_F_T10_PI, | ||
| 942 | }; | 994 | }; |
| 943 | 995 | ||
| 944 | static struct virtio_driver virtio_scsi_driver = { | 996 | static struct virtio_driver virtio_scsi_driver = { |
