Skip to content

Commit 85617dc

Browse files
jgross1David Vrabel
authored andcommitted
xen: support suspend/resume in pvscsi frontend
Up to now the pvscsi frontend hasn't supported domain suspend and resume. When a domain with an assigned pvscsi device was suspended and resumed again, it was not able to use the device any more: trying to do so resulted in hanging processes. Support suspend and resume of pvscsi devices. Signed-off-by: Juergen Gross <jgross@suse.com> Signed-off-by: David Vrabel <david.vrabel@citrix.com>
1 parent 169e6cf commit 85617dc

File tree

1 file changed

+179
-35
lines changed

1 file changed

+179
-35
lines changed

drivers/scsi/xen-scsifront.c

Lines changed: 179 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363

6464
#define VSCSIFRONT_OP_ADD_LUN 1
6565
#define VSCSIFRONT_OP_DEL_LUN 2
66+
#define VSCSIFRONT_OP_READD_LUN 3
6667

6768
/* Tuning point. */
6869
#define VSCSIIF_DEFAULT_CMD_PER_LUN 10
@@ -113,8 +114,13 @@ struct vscsifrnt_info {
113114
DECLARE_BITMAP(shadow_free_bitmap, VSCSIIF_MAX_REQS);
114115
struct vscsifrnt_shadow *shadow[VSCSIIF_MAX_REQS];
115116

117+
/* Following items are protected by the host lock. */
116118
wait_queue_head_t wq_sync;
119+
wait_queue_head_t wq_pause;
117120
unsigned int wait_ring_available:1;
121+
unsigned int waiting_pause:1;
122+
unsigned int pause:1;
123+
unsigned callers;
118124

119125
char dev_state_path[64];
120126
struct task_struct *curr;
@@ -274,31 +280,31 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
274280
wake_up(&shadow->wq_reset);
275281
}
276282

277-
static int scsifront_cmd_done(struct vscsifrnt_info *info)
283+
static void scsifront_do_response(struct vscsifrnt_info *info,
284+
struct vscsiif_response *ring_rsp)
285+
{
286+
if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
287+
test_bit(ring_rsp->rqid, info->shadow_free_bitmap),
288+
"illegal rqid %u returned by backend!\n", ring_rsp->rqid))
289+
return;
290+
291+
if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB)
292+
scsifront_cdb_cmd_done(info, ring_rsp);
293+
else
294+
scsifront_sync_cmd_done(info, ring_rsp);
295+
}
296+
297+
static int scsifront_ring_drain(struct vscsifrnt_info *info)
278298
{
279299
struct vscsiif_response *ring_rsp;
280300
RING_IDX i, rp;
281301
int more_to_do = 0;
282-
unsigned long flags;
283-
284-
spin_lock_irqsave(info->host->host_lock, flags);
285302

286303
rp = info->ring.sring->rsp_prod;
287304
rmb(); /* ordering required respective to dom0 */
288305
for (i = info->ring.rsp_cons; i != rp; i++) {
289-
290306
ring_rsp = RING_GET_RESPONSE(&info->ring, i);
291-
292-
if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
293-
test_bit(ring_rsp->rqid, info->shadow_free_bitmap),
294-
"illegal rqid %u returned by backend!\n",
295-
ring_rsp->rqid))
296-
continue;
297-
298-
if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB)
299-
scsifront_cdb_cmd_done(info, ring_rsp);
300-
else
301-
scsifront_sync_cmd_done(info, ring_rsp);
307+
scsifront_do_response(info, ring_rsp);
302308
}
303309

304310
info->ring.rsp_cons = i;
@@ -308,6 +314,18 @@ static int scsifront_cmd_done(struct vscsifrnt_info *info)
308314
else
309315
info->ring.sring->rsp_event = i + 1;
310316

317+
return more_to_do;
318+
}
319+
320+
static int scsifront_cmd_done(struct vscsifrnt_info *info)
321+
{
322+
int more_to_do;
323+
unsigned long flags;
324+
325+
spin_lock_irqsave(info->host->host_lock, flags);
326+
327+
more_to_do = scsifront_ring_drain(info);
328+
311329
info->wait_ring_available = 0;
312330

313331
spin_unlock_irqrestore(info->host->host_lock, flags);
@@ -328,6 +346,24 @@ static irqreturn_t scsifront_irq_fn(int irq, void *dev_id)
328346
return IRQ_HANDLED;
329347
}
330348

349+
static void scsifront_finish_all(struct vscsifrnt_info *info)
350+
{
351+
unsigned i;
352+
struct vscsiif_response resp;
353+
354+
scsifront_ring_drain(info);
355+
356+
for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
357+
if (test_bit(i, info->shadow_free_bitmap))
358+
continue;
359+
resp.rqid = i;
360+
resp.sense_len = 0;
361+
resp.rslt = DID_RESET << 16;
362+
resp.residual_len = 0;
363+
scsifront_do_response(info, &resp);
364+
}
365+
}
366+
331367
static int map_data_for_request(struct vscsifrnt_info *info,
332368
struct scsi_cmnd *sc,
333369
struct vscsiif_request *ring_req,
@@ -475,6 +511,27 @@ static struct vscsiif_request *scsifront_command2ring(
475511
return ring_req;
476512
}
477513

514+
static int scsifront_enter(struct vscsifrnt_info *info)
515+
{
516+
if (info->pause)
517+
return 1;
518+
info->callers++;
519+
return 0;
520+
}
521+
522+
static void scsifront_return(struct vscsifrnt_info *info)
523+
{
524+
info->callers--;
525+
if (info->callers)
526+
return;
527+
528+
if (!info->waiting_pause)
529+
return;
530+
531+
info->waiting_pause = 0;
532+
wake_up(&info->wq_pause);
533+
}
534+
478535
static int scsifront_queuecommand(struct Scsi_Host *shost,
479536
struct scsi_cmnd *sc)
480537
{
@@ -486,6 +543,10 @@ static int scsifront_queuecommand(struct Scsi_Host *shost,
486543
uint16_t rqid;
487544

488545
spin_lock_irqsave(shost->host_lock, flags);
546+
if (scsifront_enter(info)) {
547+
spin_unlock_irqrestore(shost->host_lock, flags);
548+
return SCSI_MLQUEUE_HOST_BUSY;
549+
}
489550
if (RING_FULL(&info->ring))
490551
goto busy;
491552

@@ -505,6 +566,7 @@ static int scsifront_queuecommand(struct Scsi_Host *shost,
505566
if (err < 0) {
506567
pr_debug("%s: err %d\n", __func__, err);
507568
scsifront_put_rqid(info, rqid);
569+
scsifront_return(info);
508570
spin_unlock_irqrestore(shost->host_lock, flags);
509571
if (err == -ENOMEM)
510572
return SCSI_MLQUEUE_HOST_BUSY;
@@ -514,11 +576,13 @@ static int scsifront_queuecommand(struct Scsi_Host *shost,
514576
}
515577

516578
scsifront_do_request(info);
579+
scsifront_return(info);
517580
spin_unlock_irqrestore(shost->host_lock, flags);
518581

519582
return 0;
520583

521584
busy:
585+
scsifront_return(info);
522586
spin_unlock_irqrestore(shost->host_lock, flags);
523587
pr_debug("%s: busy\n", __func__);
524588
return SCSI_MLQUEUE_HOST_BUSY;
@@ -549,7 +613,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act)
549613
if (ring_req)
550614
break;
551615
}
552-
if (err) {
616+
if (err || info->pause) {
553617
spin_unlock_irq(host->host_lock);
554618
kfree(shadow);
555619
return FAILED;
@@ -561,6 +625,11 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act)
561625
spin_lock_irq(host->host_lock);
562626
}
563627

628+
if (scsifront_enter(info)) {
629+
spin_unlock_irq(host->host_lock);
630+
return FAILED;
631+
}
632+
564633
ring_req->act = act;
565634
ring_req->ref_rqid = s->rqid;
566635

@@ -587,6 +656,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act)
587656
err = FAILED;
588657
}
589658

659+
scsifront_return(info);
590660
spin_unlock_irq(host->host_lock);
591661
return err;
592662
}
@@ -698,6 +768,13 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info)
698768
return err;
699769
}
700770

771+
static void scsifront_free_ring(struct vscsifrnt_info *info)
772+
{
773+
unbind_from_irqhandler(info->irq, info);
774+
gnttab_end_foreign_access(info->ring_ref, 0,
775+
(unsigned long)info->ring.sring);
776+
}
777+
701778
static int scsifront_init_ring(struct vscsifrnt_info *info)
702779
{
703780
struct xenbus_device *dev = info->dev;
@@ -744,9 +821,7 @@ static int scsifront_init_ring(struct vscsifrnt_info *info)
744821
fail:
745822
xenbus_transaction_end(xbt, 1);
746823
free_sring:
747-
unbind_from_irqhandler(info->irq, info);
748-
gnttab_end_foreign_access(info->ring_ref, 0,
749-
(unsigned long)info->ring.sring);
824+
scsifront_free_ring(info);
750825

751826
return err;
752827
}
@@ -779,6 +854,7 @@ static int scsifront_probe(struct xenbus_device *dev,
779854
}
780855

781856
init_waitqueue_head(&info->wq_sync);
857+
init_waitqueue_head(&info->wq_pause);
782858
spin_lock_init(&info->shadow_lock);
783859

784860
snprintf(name, TASK_COMM_LEN, "vscsiif.%d", host->host_no);
@@ -802,13 +878,60 @@ static int scsifront_probe(struct xenbus_device *dev,
802878
return 0;
803879

804880
free_sring:
805-
unbind_from_irqhandler(info->irq, info);
806-
gnttab_end_foreign_access(info->ring_ref, 0,
807-
(unsigned long)info->ring.sring);
881+
scsifront_free_ring(info);
808882
scsi_host_put(host);
809883
return err;
810884
}
811885

886+
static int scsifront_resume(struct xenbus_device *dev)
887+
{
888+
struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
889+
struct Scsi_Host *host = info->host;
890+
int err;
891+
892+
spin_lock_irq(host->host_lock);
893+
894+
/* Finish all still pending commands. */
895+
scsifront_finish_all(info);
896+
897+
spin_unlock_irq(host->host_lock);
898+
899+
/* Reconnect to dom0. */
900+
scsifront_free_ring(info);
901+
err = scsifront_init_ring(info);
902+
if (err) {
903+
dev_err(&dev->dev, "fail to resume %d\n", err);
904+
scsi_host_put(host);
905+
return err;
906+
}
907+
908+
xenbus_switch_state(dev, XenbusStateInitialised);
909+
910+
return 0;
911+
}
912+
913+
static int scsifront_suspend(struct xenbus_device *dev)
914+
{
915+
struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
916+
struct Scsi_Host *host = info->host;
917+
int err = 0;
918+
919+
/* No new commands for the backend. */
920+
spin_lock_irq(host->host_lock);
921+
info->pause = 1;
922+
while (info->callers && !err) {
923+
info->waiting_pause = 1;
924+
info->wait_ring_available = 0;
925+
spin_unlock_irq(host->host_lock);
926+
wake_up(&info->wq_sync);
927+
err = wait_event_interruptible(info->wq_pause,
928+
!info->waiting_pause);
929+
spin_lock_irq(host->host_lock);
930+
}
931+
spin_unlock_irq(host->host_lock);
932+
return err;
933+
}
934+
812935
static int scsifront_remove(struct xenbus_device *dev)
813936
{
814937
struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
@@ -823,10 +946,7 @@ static int scsifront_remove(struct xenbus_device *dev)
823946
}
824947
mutex_unlock(&scsifront_mutex);
825948

826-
gnttab_end_foreign_access(info->ring_ref, 0,
827-
(unsigned long)info->ring.sring);
828-
unbind_from_irqhandler(info->irq, info);
829-
949+
scsifront_free_ring(info);
830950
scsi_host_put(info->host);
831951

832952
return 0;
@@ -919,6 +1039,12 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
9191039
scsi_device_put(sdev);
9201040
}
9211041
break;
1042+
case VSCSIFRONT_OP_READD_LUN:
1043+
if (device_state == XenbusStateConnected)
1044+
xenbus_printf(XBT_NIL, dev->nodename,
1045+
info->dev_state_path,
1046+
"%d", XenbusStateConnected);
1047+
break;
9221048
default:
9231049
break;
9241050
}
@@ -932,21 +1058,29 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
9321058
static void scsifront_read_backend_params(struct xenbus_device *dev,
9331059
struct vscsifrnt_info *info)
9341060
{
935-
unsigned int sg_grant;
1061+
unsigned int sg_grant, nr_segs;
9361062
int ret;
9371063
struct Scsi_Host *host = info->host;
9381064

9391065
ret = xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg-grant", "%u",
9401066
&sg_grant);
941-
if (ret == 1 && sg_grant) {
942-
sg_grant = min_t(unsigned int, sg_grant, SG_ALL);
943-
sg_grant = max_t(unsigned int, sg_grant, VSCSIIF_SG_TABLESIZE);
944-
host->sg_tablesize = min_t(unsigned int, sg_grant,
1067+
if (ret != 1)
1068+
sg_grant = 0;
1069+
nr_segs = min_t(unsigned int, sg_grant, SG_ALL);
1070+
nr_segs = max_t(unsigned int, nr_segs, VSCSIIF_SG_TABLESIZE);
1071+
nr_segs = min_t(unsigned int, nr_segs,
9451072
VSCSIIF_SG_TABLESIZE * PAGE_SIZE /
9461073
sizeof(struct scsiif_request_segment));
947-
host->max_sectors = (host->sg_tablesize - 1) * PAGE_SIZE / 512;
948-
}
949-
dev_info(&dev->dev, "using up to %d SG entries\n", host->sg_tablesize);
1074+
1075+
if (!info->pause && sg_grant)
1076+
dev_info(&dev->dev, "using up to %d SG entries\n", nr_segs);
1077+
else if (info->pause && nr_segs < host->sg_tablesize)
1078+
dev_warn(&dev->dev,
1079+
"SG entries decreased from %d to %u - device may not work properly anymore\n",
1080+
host->sg_tablesize, nr_segs);
1081+
1082+
host->sg_tablesize = nr_segs;
1083+
host->max_sectors = (nr_segs - 1) * PAGE_SIZE / 512;
9501084
}
9511085

9521086
static void scsifront_backend_changed(struct xenbus_device *dev,
@@ -965,6 +1099,14 @@ static void scsifront_backend_changed(struct xenbus_device *dev,
9651099

9661100
case XenbusStateConnected:
9671101
scsifront_read_backend_params(dev, info);
1102+
1103+
if (info->pause) {
1104+
scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_READD_LUN);
1105+
xenbus_switch_state(dev, XenbusStateConnected);
1106+
info->pause = 0;
1107+
return;
1108+
}
1109+
9681110
if (xenbus_read_driver_state(dev->nodename) ==
9691111
XenbusStateInitialised)
9701112
scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
@@ -1002,6 +1144,8 @@ static struct xenbus_driver scsifront_driver = {
10021144
.ids = scsifront_ids,
10031145
.probe = scsifront_probe,
10041146
.remove = scsifront_remove,
1147+
.resume = scsifront_resume,
1148+
.suspend = scsifront_suspend,
10051149
.otherend_changed = scsifront_backend_changed,
10061150
};
10071151

0 commit comments

Comments
 (0)