diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 5 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 64 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 5 |
4 files changed, 72 insertions, 4 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index ec3f664f6c80..49d5fc729bef 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -913,6 +913,8 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | |||
913 | unit->sysfs_device.release = zfcp_sysfs_unit_release; | 913 | unit->sysfs_device.release = zfcp_sysfs_unit_release; |
914 | dev_set_drvdata(&unit->sysfs_device, unit); | 914 | dev_set_drvdata(&unit->sysfs_device, unit); |
915 | 915 | ||
916 | init_waitqueue_head(&unit->scsi_scan_wq); | ||
917 | |||
916 | /* mark unit unusable as long as sysfs registration is not complete */ | 918 | /* mark unit unusable as long as sysfs registration is not complete */ |
917 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 919 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
918 | 920 | ||
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 32933ed54b8a..07b0957b82f3 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -637,6 +637,7 @@ do { \ | |||
637 | #define ZFCP_STATUS_UNIT_SHARED 0x00000004 | 637 | #define ZFCP_STATUS_UNIT_SHARED 0x00000004 |
638 | #define ZFCP_STATUS_UNIT_READONLY 0x00000008 | 638 | #define ZFCP_STATUS_UNIT_READONLY 0x00000008 |
639 | #define ZFCP_STATUS_UNIT_REGISTERED 0x00000010 | 639 | #define ZFCP_STATUS_UNIT_REGISTERED 0x00000010 |
640 | #define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020 | ||
640 | 641 | ||
641 | /* FSF request status (this does not have a common part) */ | 642 | /* FSF request status (this does not have a common part) */ |
642 | #define ZFCP_STATUS_FSFREQ_NOT_INIT 0x00000000 | 643 | #define ZFCP_STATUS_FSFREQ_NOT_INIT 0x00000000 |
@@ -980,6 +981,10 @@ struct zfcp_unit { | |||
980 | struct scsi_device *device; /* scsi device struct pointer */ | 981 | struct scsi_device *device; /* scsi device struct pointer */ |
981 | struct zfcp_erp_action erp_action; /* pending error recovery */ | 982 | struct zfcp_erp_action erp_action; /* pending error recovery */ |
982 | atomic_t erp_counter; | 983 | atomic_t erp_counter; |
984 | wait_queue_head_t scsi_scan_wq; /* can be used to wait until | ||
985 | all scsi_scan_target | ||
986 | requests have been | ||
987 | completed. */ | ||
983 | }; | 988 | }; |
984 | 989 | ||
985 | /* FSF request */ | 990 | /* FSF request */ |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index f326bbe49fa7..885572300589 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1591,6 +1591,62 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result) | |||
1591 | return result; | 1591 | return result; |
1592 | } | 1592 | } |
1593 | 1593 | ||
1594 | struct zfcp_erp_add_work { | ||
1595 | struct zfcp_unit *unit; | ||
1596 | struct work_struct work; | ||
1597 | }; | ||
1598 | |||
1599 | /** | ||
1600 | * zfcp_erp_scsi_scan | ||
1601 | * @data: pointer to a struct zfcp_erp_add_work | ||
1602 | * | ||
1603 | * Registers a logical unit with the SCSI stack. | ||
1604 | */ | ||
1605 | static void zfcp_erp_scsi_scan(struct work_struct *work) | ||
1606 | { | ||
1607 | struct zfcp_erp_add_work *p = | ||
1608 | container_of(work, struct zfcp_erp_add_work, work); | ||
1609 | struct zfcp_unit *unit = p->unit; | ||
1610 | struct fc_rport *rport = unit->port->rport; | ||
1611 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
1612 | unit->scsi_lun, 0); | ||
1613 | atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1614 | wake_up(&unit->scsi_scan_wq); | ||
1615 | zfcp_unit_put(unit); | ||
1616 | kfree(p); | ||
1617 | } | ||
1618 | |||
1619 | /** | ||
1620 | * zfcp_erp_schedule_work | ||
1621 | * @unit: pointer to unit which should be registered with SCSI stack | ||
1622 | * | ||
1623 | * Schedules work which registers a unit with the SCSI stack | ||
1624 | */ | ||
1625 | static void | ||
1626 | zfcp_erp_schedule_work(struct zfcp_unit *unit) | ||
1627 | { | ||
1628 | struct zfcp_erp_add_work *p; | ||
1629 | |||
1630 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
1631 | if (!p) { | ||
1632 | ZFCP_LOG_NORMAL("error: Out of resources. Could not register " | ||
1633 | "the FCP-LUN 0x%Lx connected to " | ||
1634 | "the port with WWPN 0x%Lx connected to " | ||
1635 | "the adapter %s with the SCSI stack.\n", | ||
1636 | unit->fcp_lun, | ||
1637 | unit->port->wwpn, | ||
1638 | zfcp_get_busid_by_unit(unit)); | ||
1639 | return; | ||
1640 | } | ||
1641 | |||
1642 | zfcp_unit_get(unit); | ||
1643 | memset(p, 0, sizeof(*p)); | ||
1644 | atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1645 | INIT_WORK(&p->work, zfcp_erp_scsi_scan); | ||
1646 | p->unit = unit; | ||
1647 | schedule_work(&p->work); | ||
1648 | } | ||
1649 | |||
1594 | /* | 1650 | /* |
1595 | * function: | 1651 | * function: |
1596 | * | 1652 | * |
@@ -3092,9 +3148,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, | |||
3092 | && port->rport) { | 3148 | && port->rport) { |
3093 | atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, | 3149 | atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, |
3094 | &unit->status); | 3150 | &unit->status); |
3095 | scsi_scan_target(&port->rport->dev, 0, | 3151 | if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, |
3096 | port->rport->scsi_target_id, | 3152 | &unit->status) == 0) |
3097 | unit->scsi_lun, 0); | 3153 | zfcp_erp_schedule_work(unit); |
3098 | } | 3154 | } |
3099 | zfcp_unit_put(unit); | 3155 | zfcp_unit_put(unit); |
3100 | break; | 3156 | break; |
@@ -3121,7 +3177,7 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, | |||
3121 | zfcp_get_busid_by_port(port), | 3177 | zfcp_get_busid_by_port(port), |
3122 | port->wwpn); | 3178 | port->wwpn); |
3123 | else { | 3179 | else { |
3124 | scsi_flush_work(adapter->scsi_host); | 3180 | scsi_target_unblock(&port->rport->dev); |
3125 | port->rport->maxframe_size = port->maxframe_size; | 3181 | port->rport->maxframe_size = port->maxframe_size; |
3126 | port->rport->supported_classes = | 3182 | port->rport->supported_classes = |
3127 | port->supported_classes; | 3183 | port->supported_classes; |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 99db02062c3b..e742b3de16ac 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI | 22 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI |
23 | 23 | ||
24 | #include "zfcp_ext.h" | 24 | #include "zfcp_ext.h" |
25 | #include <asm/atomic.h> | ||
25 | 26 | ||
26 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); | 27 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); |
27 | static int zfcp_scsi_slave_alloc(struct scsi_device *sdp); | 28 | static int zfcp_scsi_slave_alloc(struct scsi_device *sdp); |
@@ -179,6 +180,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | |||
179 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; | 180 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; |
180 | 181 | ||
181 | if (unit) { | 182 | if (unit) { |
183 | zfcp_erp_wait(unit->port->adapter); | ||
184 | wait_event(unit->scsi_scan_wq, | ||
185 | atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, | ||
186 | &unit->status) == 0); | ||
182 | atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); | 187 | atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); |
183 | sdpnt->hostdata = NULL; | 188 | sdpnt->hostdata = NULL; |
184 | unit->device = NULL; | 189 | unit->device = NULL; |