Re: [PATCH 1/3] virtio-scsi: implement target rescan

2017-12-15 Thread Steffen Maier


On 12/14/2017 11:11 AM, Hannes Reinecke wrote:

Implement the 'rescan' virtio-scsi feature. Rescanning works by
sending a 'rescan' virtio-scsi command with the next requested
target id to the backend. The backend will respond with the next
used target id or '-1' if no more targets are found.
This avoids scanning all possible targets.

Signed-off-by: Hannes Reinecke 
---
  drivers/scsi/virtio_scsi.c   | 239 ++-
  include/uapi/linux/virtio_scsi.h |  15 +++
  2 files changed, 250 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 7c28e8d..a561e90 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c



+static void virtscsi_rescan_work(struct work_struct *work)
+{



+   if (target_id == -1) {
+   shost_printk(KERN_INFO, sh, "rescan: terminated\n");
+   spin_unlock_irq(>rescan_lock);
+   return;
+   }
+   spin_unlock_irq(>rescan_lock);
+
+   cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
+   if (!cmd) {
+   shost_printk(KERN_INFO, sh, "rescan: no memory\n");
+   goto scan_host;
+   }
+   shost_printk(KERN_INFO, sh, "rescan: next target %d\n", target_id);



+   shost_printk(KERN_INFO, sh,
+"rescan: no more targets\n");



+   shost_printk(KERN_INFO, sh, "rescan: scan host\n");
+   scsi_scan_host(sh);
+}
+
+static void virtscsi_scan_host(struct virtio_scsi *vscsi)
+{
+   struct Scsi_Host *sh = virtio_scsi_host(vscsi->vdev);
+   int ret;
+   struct virtio_scsi_cmd *cmd;
+   DECLARE_COMPLETION_ONSTACK(comp);
+
+   cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
+   if (!cmd) {
+   shost_printk(KERN_INFO, sh, "rescan: no memory\n");


If shost_printk does not add any info about calling function, this 
cannot be distinguished from a message with the same format string above 
in virtscsi_rescan_work()?



+   return;
+   }
+   shost_printk(KERN_INFO, sh, "rescan: scan host\n");


dito



+static void virtscsi_scan_start(struct Scsi_Host *sh)
+{
+   struct virtio_scsi *vscsi = shost_priv(sh);
+
+   virtscsi_scan_host(vscsi);
+   spin_lock_irq(>rescan_lock);
+   if (vscsi->next_target_id != -1) {
+   shost_printk(KERN_INFO, sh, "rescan: already running\n");
+   spin_unlock_irq(>rescan_lock);
+   return;
+   }
+   vscsi->next_target_id = 0;
+   shost_printk(KERN_INFO, sh, "rescan: start\n");
+   spin_unlock_irq(>rescan_lock);
+   queue_work(system_freezable_wq, >rescan_work);
+}
+
+int virtscsi_scan_finished(struct Scsi_Host *sh, unsigned long time)



+   shost_printk(KERN_INFO, sh, "rescan: %s finished\n",
+ret ? "" : "not");
+   return ret;
+}



--
Mit freundlichen Grüßen / Kind regards
Steffen Maier

Linux on z Systems Development

IBM Deutschland Research & Development GmbH
Vorsitzende des Aufsichtsrats: Martina Koederitz
Geschaeftsfuehrung: Dirk Wittkopp
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294



[PATCH 1/3] virtio-scsi: implement target rescan

2017-12-14 Thread Hannes Reinecke
Implement the 'rescan' virtio-scsi feature. Rescanning works by
sending a 'rescan' virtio-scsi command with the next requested
target id to the backend. The backend will respond with the next
used target id or '-1' if no more targets are found.
This avoids scanning all possible targets.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/virtio_scsi.c   | 239 ++-
 include/uapi/linux/virtio_scsi.h |  15 +++
 2 files changed, 250 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 7c28e8d..a561e90 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -46,12 +46,14 @@ struct virtio_scsi_cmd {
struct virtio_scsi_cmd_req_picmd_pi;
struct virtio_scsi_ctrl_tmf_req  tmf;
struct virtio_scsi_ctrl_an_req   an;
+   struct virtio_scsi_rescan_reqrescan;
} req;
union {
struct virtio_scsi_cmd_resp  cmd;
struct virtio_scsi_ctrl_tmf_resp tmf;
struct virtio_scsi_ctrl_an_resp  an;
struct virtio_scsi_event evt;
+   struct virtio_scsi_rescan_resp   rescan;
} resp;
 } cacheline_aligned_in_smp;
 
@@ -115,6 +117,10 @@ struct virtio_scsi {
/* Protected by event_vq lock */
bool stop_events;
 
+   int next_target_id;
+   struct work_struct rescan_work;
+   spinlock_t rescan_lock;
+
struct virtio_scsi_vq ctrl_vq;
struct virtio_scsi_vq event_vq;
struct virtio_scsi_vq req_vqs[];
@@ -318,6 +324,11 @@ static void virtscsi_cancel_event_work(struct virtio_scsi 
*vscsi)
 
for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++)
cancel_work_sync(>event_list[i].work);
+
+   spin_lock_irq(>rescan_lock);
+   vscsi->next_target_id = -1;
+   spin_unlock_irq(>rescan_lock);
+   cancel_work_sync(>rescan_work);
 }
 
 static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi,
@@ -805,6 +816,168 @@ static enum blk_eh_timer_return 
virtscsi_eh_timed_out(struct scsi_cmnd *scmnd)
return BLK_EH_RESET_TIMER;
 }
 
+static void virtscsi_rescan_work(struct work_struct *work)
+{
+   struct virtio_scsi *vscsi =
+   container_of(work, struct virtio_scsi, rescan_work);
+   struct Scsi_Host *sh = virtio_scsi_host(vscsi->vdev);
+   int target_id, ret;
+   struct virtio_scsi_cmd *cmd;
+   DECLARE_COMPLETION_ONSTACK(comp);
+
+   spin_lock_irq(>rescan_lock);
+   target_id = vscsi->next_target_id;
+   if (target_id == -1) {
+   shost_printk(KERN_INFO, sh, "rescan: terminated\n");
+   spin_unlock_irq(>rescan_lock);
+   return;
+   }
+   spin_unlock_irq(>rescan_lock);
+
+   cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
+   if (!cmd) {
+   shost_printk(KERN_INFO, sh, "rescan: no memory\n");
+   goto scan_host;
+   }
+   shost_printk(KERN_INFO, sh, "rescan: next target %d\n", target_id);
+   memset(cmd, 0, sizeof(*cmd));
+   cmd->comp = 
+   cmd->sc = NULL;
+   cmd->req.rescan = (struct virtio_scsi_rescan_req){
+   .type = VIRTIO_SCSI_T_RESCAN,
+   .next_id = cpu_to_virtio32(vscsi->vdev, target_id),
+   };
+
+   ret = virtscsi_kick_cmd(>ctrl_vq, cmd, sizeof(cmd->req.rescan),
+   sizeof(cmd->resp.rescan));
+   if (ret < 0) {
+   mempool_free(cmd, virtscsi_cmd_pool);
+   goto scan_host;
+   }
+
+   wait_for_completion();
+   target_id = virtio32_to_cpu(vscsi->vdev, cmd->resp.rescan.id);
+   if (target_id != -1) {
+   int transport = virtio32_to_cpu(vscsi->vdev,
+   cmd->resp.rescan.transport);
+   spin_lock_irq(>rescan_lock);
+   vscsi->next_target_id = target_id + 1;
+   spin_unlock_irq(>rescan_lock);
+   shost_printk(KERN_INFO, sh,
+"found %s target %d (WWN %*phN)\n",
+transport == SCSI_PROTOCOL_FCP ? "FC" : "SAS",
+target_id, 8,
+cmd->resp.rescan.port_wwn);
+   scsi_scan_target(>shost_gendev, 0, target_id,
+SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
+   queue_work(system_freezable_wq, >rescan_work);
+   } else {
+   shost_printk(KERN_INFO, sh,
+"rescan: no more targets\n");
+   spin_lock_irq(>rescan_lock);
+   vscsi->next_target_id = -1;
+   spin_unlock_irq(>rescan_lock);
+   }
+   mempool_free(cmd, virtscsi_cmd_pool);
+   return;
+scan_host:
+   spin_lock_irq(>rescan_lock);
+   vscsi->next_target_id = -1;
+   spin_unlock_irq(>rescan_lock);
+