aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/virtio_scsi.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-06-13 10:56:34 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-07-20 03:58:58 -0400
commit2bd37f0fde99cbf8b78fb55f1128e8c3a63cf1da (patch)
tree669df2ebb154fff1af3590bd2bf815083857e01d /drivers/scsi/virtio_scsi.c
parentbce750b1633927be3eecf821f4d17975c3ba5b6a (diff)
[SCSI] virtio-scsi: split scatterlist per target
To improve performance for I/O to different targets, add a separate scatterlist for each of them. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/virtio_scsi.c')
-rw-r--r--drivers/scsi/virtio_scsi.c141
1 files changed, 94 insertions, 47 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index facfc90ef005..9fc5e67a0ca5 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -50,18 +50,24 @@ struct virtio_scsi_vq {
50 struct virtqueue *vq; 50 struct virtqueue *vq;
51}; 51};
52 52
53/* Per-target queue state */
54struct virtio_scsi_target_state {
55 /* Protects sg. Lock hierarchy is tgt_lock -> vq_lock. */
56 spinlock_t tgt_lock;
57
58 /* For sglist construction when adding commands to the virtqueue. */
59 struct scatterlist sg[];
60};
61
53/* Driver instance state */ 62/* Driver instance state */
54struct virtio_scsi { 63struct virtio_scsi {
55 /* Protects sg[]. The lock hierarchy is sg_lock -> vq_lock. */
56 spinlock_t sg_lock;
57
58 struct virtio_device *vdev; 64 struct virtio_device *vdev;
65
59 struct virtio_scsi_vq ctrl_vq; 66 struct virtio_scsi_vq ctrl_vq;
60 struct virtio_scsi_vq event_vq; 67 struct virtio_scsi_vq event_vq;
61 struct virtio_scsi_vq req_vq; 68 struct virtio_scsi_vq req_vq;
62 69
63 /* For sglist construction when adding commands to the virtqueue. */ 70 struct virtio_scsi_target_state *tgt[];
64 struct scatterlist sg[];
65}; 71};
66 72
67static struct kmem_cache *virtscsi_cmd_cache; 73static struct kmem_cache *virtscsi_cmd_cache;
@@ -230,25 +236,17 @@ static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx,
230 * @req_size : size of the request buffer 236 * @req_size : size of the request buffer
231 * @resp_size : size of the response buffer 237 * @resp_size : size of the response buffer
232 * 238 *
233 * Called with vq_lock held. 239 * Called with tgt_lock held.
234 */ 240 */
235static void virtscsi_map_cmd(struct virtio_scsi *vscsi, 241static void virtscsi_map_cmd(struct virtio_scsi_target_state *tgt,
236 struct virtio_scsi_cmd *cmd, 242 struct virtio_scsi_cmd *cmd,
237 unsigned *out_num, unsigned *in_num, 243 unsigned *out_num, unsigned *in_num,
238 size_t req_size, size_t resp_size) 244 size_t req_size, size_t resp_size)
239{ 245{
240 struct scsi_cmnd *sc = cmd->sc; 246 struct scsi_cmnd *sc = cmd->sc;
241 struct scatterlist *sg = vscsi->sg; 247 struct scatterlist *sg = tgt->sg;
242 unsigned int idx = 0; 248 unsigned int idx = 0;
243 249
244 if (sc) {
245 struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
246 BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
247
248 /* TODO: check feature bit and fail if unsupported? */
249 BUG_ON(sc->sc_data_direction == DMA_BIDIRECTIONAL);
250 }
251
252 /* Request header. */ 250 /* Request header. */
253 sg_set_buf(&sg[idx++], &cmd->req, req_size); 251 sg_set_buf(&sg[idx++], &cmd->req, req_size);
254 252
@@ -268,7 +266,8 @@ static void virtscsi_map_cmd(struct virtio_scsi *vscsi,
268 *in_num = idx - *out_num; 266 *in_num = idx - *out_num;
269} 267}
270 268
271static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtio_scsi_vq *vq, 269static int virtscsi_kick_cmd(struct virtio_scsi_target_state *tgt,
270 struct virtio_scsi_vq *vq,
272 struct virtio_scsi_cmd *cmd, 271 struct virtio_scsi_cmd *cmd,
273 size_t req_size, size_t resp_size, gfp_t gfp) 272 size_t req_size, size_t resp_size, gfp_t gfp)
274{ 273{
@@ -276,12 +275,12 @@ static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtio_scsi_vq *v
276 unsigned long flags; 275 unsigned long flags;
277 int ret; 276 int ret;
278 277
279 spin_lock_irqsave(&vscsi->sg_lock, flags); 278 spin_lock_irqsave(&tgt->tgt_lock, flags);
280 virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size); 279 virtscsi_map_cmd(tgt, cmd, &out_num, &in_num, req_size, resp_size);
281 280
282 spin_lock(&vq->vq_lock); 281 spin_lock(&vq->vq_lock);
283 ret = virtqueue_add_buf(vq->vq, vscsi->sg, out_num, in_num, cmd, gfp); 282 ret = virtqueue_add_buf(vq->vq, tgt->sg, out_num, in_num, cmd, gfp);
284 spin_unlock(&vscsi->sg_lock); 283 spin_unlock(&tgt->tgt_lock);
285 if (ret >= 0) 284 if (ret >= 0)
286 ret = virtqueue_kick_prepare(vq->vq); 285 ret = virtqueue_kick_prepare(vq->vq);
287 286
@@ -295,9 +294,16 @@ static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtio_scsi_vq *v
295static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) 294static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
296{ 295{
297 struct virtio_scsi *vscsi = shost_priv(sh); 296 struct virtio_scsi *vscsi = shost_priv(sh);
297 struct virtio_scsi_target_state *tgt = vscsi->tgt[sc->device->id];
298 struct virtio_scsi_cmd *cmd; 298 struct virtio_scsi_cmd *cmd;
299 int ret; 299 int ret;
300 300
301 struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
302 BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
303
304 /* TODO: check feature bit and fail if unsupported? */
305 BUG_ON(sc->sc_data_direction == DMA_BIDIRECTIONAL);
306
301 dev_dbg(&sc->device->sdev_gendev, 307 dev_dbg(&sc->device->sdev_gendev,
302 "cmd %p CDB: %#02x\n", sc, sc->cmnd[0]); 308 "cmd %p CDB: %#02x\n", sc, sc->cmnd[0]);
303 309
@@ -322,7 +328,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
322 BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); 328 BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE);
323 memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); 329 memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
324 330
325 if (virtscsi_kick_cmd(vscsi, &vscsi->req_vq, cmd, 331 if (virtscsi_kick_cmd(tgt, &vscsi->req_vq, cmd,
326 sizeof cmd->req.cmd, sizeof cmd->resp.cmd, 332 sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
327 GFP_ATOMIC) >= 0) 333 GFP_ATOMIC) >= 0)
328 ret = 0; 334 ret = 0;
@@ -334,10 +340,11 @@ out:
334static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) 340static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
335{ 341{
336 DECLARE_COMPLETION_ONSTACK(comp); 342 DECLARE_COMPLETION_ONSTACK(comp);
343 struct virtio_scsi_target_state *tgt = vscsi->tgt[cmd->sc->device->id];
337 int ret = FAILED; 344 int ret = FAILED;
338 345
339 cmd->comp = &comp; 346 cmd->comp = &comp;
340 if (virtscsi_kick_cmd(vscsi, &vscsi->ctrl_vq, cmd, 347 if (virtscsi_kick_cmd(tgt, &vscsi->ctrl_vq, cmd,
341 sizeof cmd->req.tmf, sizeof cmd->resp.tmf, 348 sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
342 GFP_NOIO) < 0) 349 GFP_NOIO) < 0)
343 goto out; 350 goto out;
@@ -437,11 +444,49 @@ static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
437 virtscsi_vq->vq = vq; 444 virtscsi_vq->vq = vq;
438} 445}
439 446
447static struct virtio_scsi_target_state *virtscsi_alloc_tgt(
448 struct virtio_device *vdev, int sg_elems)
449{
450 struct virtio_scsi_target_state *tgt;
451 gfp_t gfp_mask = GFP_KERNEL;
452
453 /* We need extra sg elements at head and tail. */
454 tgt = kmalloc(sizeof(*tgt) + sizeof(tgt->sg[0]) * (sg_elems + 2),
455 gfp_mask);
456
457 if (!tgt)
458 return NULL;
459
460 spin_lock_init(&tgt->tgt_lock);
461 sg_init_table(tgt->sg, sg_elems + 2);
462 return tgt;
463}
464
465static void virtscsi_remove_vqs(struct virtio_device *vdev)
466{
467 struct Scsi_Host *sh = virtio_scsi_host(vdev);
468 struct virtio_scsi *vscsi = shost_priv(sh);
469 u32 i, num_targets;
470
471 /* Stop all the virtqueues. */
472 vdev->config->reset(vdev);
473
474 num_targets = sh->max_id;
475 for (i = 0; i < num_targets; i++) {
476 kfree(vscsi->tgt[i]);
477 vscsi->tgt[i] = NULL;
478 }
479
480 vdev->config->del_vqs(vdev);
481}
482
440static int virtscsi_init(struct virtio_device *vdev, 483static int virtscsi_init(struct virtio_device *vdev,
441 struct virtio_scsi *vscsi) 484 struct virtio_scsi *vscsi, int num_targets)
442{ 485{
443 int err; 486 int err;
444 struct virtqueue *vqs[3]; 487 struct virtqueue *vqs[3];
488 u32 i, sg_elems;
489
445 vq_callback_t *callbacks[] = { 490 vq_callback_t *callbacks[] = {
446 virtscsi_ctrl_done, 491 virtscsi_ctrl_done,
447 virtscsi_event_done, 492 virtscsi_event_done,
@@ -464,7 +509,23 @@ static int virtscsi_init(struct virtio_device *vdev,
464 509
465 virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE); 510 virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
466 virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE); 511 virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
467 return 0; 512
513 /* We need to know how many segments before we allocate. */
514 sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
515
516 for (i = 0; i < num_targets; i++) {
517 vscsi->tgt[i] = virtscsi_alloc_tgt(vdev, sg_elems);
518 if (!vscsi->tgt[i]) {
519 err = -ENOMEM;
520 goto out;
521 }
522 }
523 err = 0;
524
525out:
526 if (err)
527 virtscsi_remove_vqs(vdev);
528 return err;
468} 529}
469 530
470static int __devinit virtscsi_probe(struct virtio_device *vdev) 531static int __devinit virtscsi_probe(struct virtio_device *vdev)
@@ -472,31 +533,25 @@ static int __devinit virtscsi_probe(struct virtio_device *vdev)
472 struct Scsi_Host *shost; 533 struct Scsi_Host *shost;
473 struct virtio_scsi *vscsi; 534 struct virtio_scsi *vscsi;
474 int err; 535 int err;
475 u32 sg_elems; 536 u32 sg_elems, num_targets;
476 u32 cmd_per_lun; 537 u32 cmd_per_lun;
477 538
478 /* We need to know how many segments before we allocate.
479 * We need an extra sg elements at head and tail.
480 */
481 sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
482
483 /* Allocate memory and link the structs together. */ 539 /* Allocate memory and link the structs together. */
540 num_targets = virtscsi_config_get(vdev, max_target) + 1;
484 shost = scsi_host_alloc(&virtscsi_host_template, 541 shost = scsi_host_alloc(&virtscsi_host_template,
485 sizeof(*vscsi) + sizeof(vscsi->sg[0]) * (sg_elems + 2)); 542 sizeof(*vscsi)
543 + num_targets * sizeof(struct virtio_scsi_target_state));
486 544
487 if (!shost) 545 if (!shost)
488 return -ENOMEM; 546 return -ENOMEM;
489 547
548 sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
490 shost->sg_tablesize = sg_elems; 549 shost->sg_tablesize = sg_elems;
491 vscsi = shost_priv(shost); 550 vscsi = shost_priv(shost);
492 vscsi->vdev = vdev; 551 vscsi->vdev = vdev;
493 vdev->priv = shost; 552 vdev->priv = shost;
494 553
495 /* Random initializations. */ 554 err = virtscsi_init(vdev, vscsi, num_targets);
496 spin_lock_init(&vscsi->sg_lock);
497 sg_init_table(vscsi->sg, sg_elems + 2);
498
499 err = virtscsi_init(vdev, vscsi);
500 if (err) 555 if (err)
501 goto virtscsi_init_failed; 556 goto virtscsi_init_failed;
502 557
@@ -504,7 +559,7 @@ static int __devinit virtscsi_probe(struct virtio_device *vdev)
504 shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue); 559 shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
505 shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF; 560 shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF;
506 shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1; 561 shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1;
507 shost->max_id = virtscsi_config_get(vdev, max_target) + 1; 562 shost->max_id = num_targets;
508 shost->max_channel = 0; 563 shost->max_channel = 0;
509 shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; 564 shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE;
510 err = scsi_add_host(shost, &vdev->dev); 565 err = scsi_add_host(shost, &vdev->dev);
@@ -522,14 +577,6 @@ virtscsi_init_failed:
522 return err; 577 return err;
523} 578}
524 579
525static void virtscsi_remove_vqs(struct virtio_device *vdev)
526{
527 /* Stop all the virtqueues. */
528 vdev->config->reset(vdev);
529
530 vdev->config->del_vqs(vdev);
531}
532
533static void __devexit virtscsi_remove(struct virtio_device *vdev) 580static void __devexit virtscsi_remove(struct virtio_device *vdev)
534{ 581{
535 struct Scsi_Host *shost = virtio_scsi_host(vdev); 582 struct Scsi_Host *shost = virtio_scsi_host(vdev);
@@ -552,7 +599,7 @@ static int virtscsi_restore(struct virtio_device *vdev)
552 struct Scsi_Host *sh = virtio_scsi_host(vdev); 599 struct Scsi_Host *sh = virtio_scsi_host(vdev);
553 struct virtio_scsi *vscsi = shost_priv(sh); 600 struct virtio_scsi *vscsi = shost_priv(sh);
554 601
555 return virtscsi_init(vdev, vscsi); 602 return virtscsi_init(vdev, vscsi, sh->max_id);
556} 603}
557#endif 604#endif
558 605