diff options
| -rw-r--r-- | drivers/firewire/fw-sbp2.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 17bf0e1468e6..d334cac5e1fc 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
| @@ -173,6 +173,9 @@ struct sbp2_target { | |||
| 173 | int blocked; /* ditto */ | 173 | int blocked; /* ditto */ |
| 174 | }; | 174 | }; |
| 175 | 175 | ||
| 176 | /* Impossible login_id, to detect logout attempt before successful login */ | ||
| 177 | #define INVALID_LOGIN_ID 0x10000 | ||
| 178 | |||
| 176 | /* | 179 | /* |
| 177 | * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be | 180 | * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be |
| 178 | * provided in the config rom. Most devices do provide a value, which | 181 | * provided in the config rom. Most devices do provide a value, which |
| @@ -788,9 +791,20 @@ static void sbp2_release_target(struct kref *kref) | |||
| 788 | scsi_remove_device(sdev); | 791 | scsi_remove_device(sdev); |
| 789 | scsi_device_put(sdev); | 792 | scsi_device_put(sdev); |
| 790 | } | 793 | } |
| 791 | sbp2_send_management_orb(lu, tgt->node_id, lu->generation, | 794 | if (lu->login_id != INVALID_LOGIN_ID) { |
| 792 | SBP2_LOGOUT_REQUEST, lu->login_id, NULL); | 795 | int generation, node_id; |
| 793 | 796 | /* | |
| 797 | * tgt->node_id may be obsolete here if we failed | ||
| 798 | * during initial login or after a bus reset where | ||
| 799 | * the topology changed. | ||
| 800 | */ | ||
| 801 | generation = device->generation; | ||
| 802 | smp_rmb(); /* node_id vs. generation */ | ||
| 803 | node_id = device->node_id; | ||
| 804 | sbp2_send_management_orb(lu, node_id, generation, | ||
| 805 | SBP2_LOGOUT_REQUEST, | ||
| 806 | lu->login_id, NULL); | ||
| 807 | } | ||
| 794 | fw_core_remove_address_handler(&lu->address_handler); | 808 | fw_core_remove_address_handler(&lu->address_handler); |
| 795 | list_del(&lu->link); | 809 | list_del(&lu->link); |
| 796 | kfree(lu); | 810 | kfree(lu); |
| @@ -805,19 +819,20 @@ static void sbp2_release_target(struct kref *kref) | |||
| 805 | 819 | ||
| 806 | static struct workqueue_struct *sbp2_wq; | 820 | static struct workqueue_struct *sbp2_wq; |
| 807 | 821 | ||
| 822 | static void sbp2_target_put(struct sbp2_target *tgt) | ||
| 823 | { | ||
| 824 | kref_put(&tgt->kref, sbp2_release_target); | ||
| 825 | } | ||
| 826 | |||
| 808 | /* | 827 | /* |
| 809 | * Always get the target's kref when scheduling work on one its units. | 828 | * Always get the target's kref when scheduling work on one its units. |
| 810 | * Each workqueue job is responsible to call sbp2_target_put() upon return. | 829 | * Each workqueue job is responsible to call sbp2_target_put() upon return. |
| 811 | */ | 830 | */ |
| 812 | static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) | 831 | static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) |
| 813 | { | 832 | { |
| 814 | if (queue_delayed_work(sbp2_wq, &lu->work, delay)) | 833 | kref_get(&lu->tgt->kref); |
| 815 | kref_get(&lu->tgt->kref); | 834 | if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) |
| 816 | } | 835 | sbp2_target_put(lu->tgt); |
| 817 | |||
| 818 | static void sbp2_target_put(struct sbp2_target *tgt) | ||
| 819 | { | ||
| 820 | kref_put(&tgt->kref, sbp2_release_target); | ||
| 821 | } | 836 | } |
| 822 | 837 | ||
| 823 | /* | 838 | /* |
| @@ -978,6 +993,7 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) | |||
| 978 | 993 | ||
| 979 | lu->tgt = tgt; | 994 | lu->tgt = tgt; |
| 980 | lu->lun = lun_entry & 0xffff; | 995 | lu->lun = lun_entry & 0xffff; |
| 996 | lu->login_id = INVALID_LOGIN_ID; | ||
| 981 | lu->retries = 0; | 997 | lu->retries = 0; |
| 982 | lu->has_sdev = false; | 998 | lu->has_sdev = false; |
| 983 | lu->blocked = false; | 999 | lu->blocked = false; |
