diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-08-27 09:34:32 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-09-16 16:23:56 -0400 |
commit | b2af07b6844aade3a6d69511625bef2b1cb609cc (patch) | |
tree | 0e2d6768fb10aeadfc1131ca6251a5bc98ccc479 /drivers/firewire | |
parent | 6ff8147d075da2e1eb69fab2ee75104c59f573e0 (diff) |
firewire: sbp2: move some code to more sensible places
Implement sbp2_queue_work(), which is now a very simple accessor to one
of the struct sbp2_logical_unit members, right after the definition of
struct sbp2_logical_unit.
Put the sbp2_reconnect() implementation right after the sbp2_login()
implementation. They are both part of the SBP-2 access protocol.
Implement the driver methods sbp2_probe(), spp2_update(), sbp2_remove()
in this order, reflecting the lifetime of an SBP-2 target.
Place the sbp2_release_target() implementation right next to
sbp2_remove() which is its primary user, and after sbp2_probe() which is
the counterpart to sbp2_release_target().
There are no changes to the implementations here, or at least not meant
to be.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/sbp2.c | 213 |
1 files changed, 107 insertions, 106 deletions
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index a2715b20ede7..09b79e940a20 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c | |||
@@ -154,6 +154,11 @@ struct sbp2_logical_unit { | |||
154 | bool blocked; | 154 | bool blocked; |
155 | }; | 155 | }; |
156 | 156 | ||
157 | static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) | ||
158 | { | ||
159 | queue_delayed_work(fw_workqueue, &lu->work, delay); | ||
160 | } | ||
161 | |||
157 | /* | 162 | /* |
158 | * We create one struct sbp2_target per IEEE 1212 Unit Directory | 163 | * We create one struct sbp2_target per IEEE 1212 Unit Directory |
159 | * and one struct Scsi_Host per sbp2_target. | 164 | * and one struct Scsi_Host per sbp2_target. |
@@ -771,52 +776,6 @@ static int sbp2_lun2int(u16 lun) | |||
771 | return scsilun_to_int(&eight_bytes_lun); | 776 | return scsilun_to_int(&eight_bytes_lun); |
772 | } | 777 | } |
773 | 778 | ||
774 | static void sbp2_release_target(struct sbp2_target *tgt) | ||
775 | { | ||
776 | struct sbp2_logical_unit *lu, *next; | ||
777 | struct Scsi_Host *shost = | ||
778 | container_of((void *)tgt, struct Scsi_Host, hostdata[0]); | ||
779 | struct scsi_device *sdev; | ||
780 | struct fw_device *device = target_device(tgt); | ||
781 | |||
782 | /* prevent deadlocks */ | ||
783 | sbp2_unblock(tgt); | ||
784 | |||
785 | list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { | ||
786 | sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun)); | ||
787 | if (sdev) { | ||
788 | scsi_remove_device(sdev); | ||
789 | scsi_device_put(sdev); | ||
790 | } | ||
791 | if (lu->login_id != INVALID_LOGIN_ID) { | ||
792 | int generation, node_id; | ||
793 | /* | ||
794 | * tgt->node_id may be obsolete here if we failed | ||
795 | * during initial login or after a bus reset where | ||
796 | * the topology changed. | ||
797 | */ | ||
798 | generation = device->generation; | ||
799 | smp_rmb(); /* node_id vs. generation */ | ||
800 | node_id = device->node_id; | ||
801 | sbp2_send_management_orb(lu, node_id, generation, | ||
802 | SBP2_LOGOUT_REQUEST, | ||
803 | lu->login_id, NULL); | ||
804 | } | ||
805 | fw_core_remove_address_handler(&lu->address_handler); | ||
806 | list_del(&lu->link); | ||
807 | kfree(lu); | ||
808 | } | ||
809 | scsi_remove_host(shost); | ||
810 | fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no); | ||
811 | |||
812 | scsi_host_put(shost); | ||
813 | } | ||
814 | |||
815 | static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) | ||
816 | { | ||
817 | queue_delayed_work(fw_workqueue, &lu->work, delay); | ||
818 | } | ||
819 | |||
820 | /* | 779 | /* |
821 | * Write retransmit retry values into the BUSY_TIMEOUT register. | 780 | * Write retransmit retry values into the BUSY_TIMEOUT register. |
822 | * - The single-phase retry protocol is supported by all SBP-2 devices, but the | 781 | * - The single-phase retry protocol is supported by all SBP-2 devices, but the |
@@ -955,6 +914,57 @@ static void sbp2_login(struct work_struct *work) | |||
955 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | 914 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); |
956 | } | 915 | } |
957 | 916 | ||
917 | static void sbp2_reconnect(struct work_struct *work) | ||
918 | { | ||
919 | struct sbp2_logical_unit *lu = | ||
920 | container_of(work, struct sbp2_logical_unit, work.work); | ||
921 | struct sbp2_target *tgt = lu->tgt; | ||
922 | struct fw_device *device = target_device(tgt); | ||
923 | int generation, node_id, local_node_id; | ||
924 | |||
925 | if (fw_device_is_shutdown(device)) | ||
926 | return; | ||
927 | |||
928 | generation = device->generation; | ||
929 | smp_rmb(); /* node IDs must not be older than generation */ | ||
930 | node_id = device->node_id; | ||
931 | local_node_id = device->card->node_id; | ||
932 | |||
933 | if (sbp2_send_management_orb(lu, node_id, generation, | ||
934 | SBP2_RECONNECT_REQUEST, | ||
935 | lu->login_id, NULL) < 0) { | ||
936 | /* | ||
937 | * If reconnect was impossible even though we are in the | ||
938 | * current generation, fall back and try to log in again. | ||
939 | * | ||
940 | * We could check for "Function rejected" status, but | ||
941 | * looking at the bus generation as simpler and more general. | ||
942 | */ | ||
943 | smp_rmb(); /* get current card generation */ | ||
944 | if (generation == device->card->generation || | ||
945 | lu->retries++ >= 5) { | ||
946 | fw_error("%s: failed to reconnect\n", tgt->bus_id); | ||
947 | lu->retries = 0; | ||
948 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | ||
949 | } | ||
950 | sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); | ||
951 | |||
952 | return; | ||
953 | } | ||
954 | |||
955 | tgt->node_id = node_id; | ||
956 | tgt->address_high = local_node_id << 16; | ||
957 | smp_wmb(); /* node IDs must not be older than generation */ | ||
958 | lu->generation = generation; | ||
959 | |||
960 | fw_notify("%s: reconnected to LUN %04x (%d retries)\n", | ||
961 | tgt->bus_id, lu->lun, lu->retries); | ||
962 | |||
963 | sbp2_agent_reset(lu); | ||
964 | sbp2_cancel_orbs(lu); | ||
965 | sbp2_conditionally_unblock(lu); | ||
966 | } | ||
967 | |||
958 | static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) | 968 | static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) |
959 | { | 969 | { |
960 | struct sbp2_logical_unit *lu; | 970 | struct sbp2_logical_unit *lu; |
@@ -1100,6 +1110,7 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, | |||
1100 | } | 1110 | } |
1101 | 1111 | ||
1102 | static struct scsi_host_template scsi_driver_template; | 1112 | static struct scsi_host_template scsi_driver_template; |
1113 | static void sbp2_release_target(struct sbp2_target *tgt); | ||
1103 | 1114 | ||
1104 | static int sbp2_probe(struct device *dev) | 1115 | static int sbp2_probe(struct device *dev) |
1105 | { | 1116 | { |
@@ -1171,87 +1182,77 @@ static int sbp2_probe(struct device *dev) | |||
1171 | return -ENOMEM; | 1182 | return -ENOMEM; |
1172 | } | 1183 | } |
1173 | 1184 | ||
1174 | static int sbp2_remove(struct device *dev) | 1185 | static void sbp2_update(struct fw_unit *unit) |
1175 | { | 1186 | { |
1176 | struct fw_unit *unit = fw_unit(dev); | ||
1177 | struct sbp2_target *tgt = dev_get_drvdata(&unit->device); | 1187 | struct sbp2_target *tgt = dev_get_drvdata(&unit->device); |
1178 | struct sbp2_logical_unit *lu; | 1188 | struct sbp2_logical_unit *lu; |
1179 | 1189 | ||
1180 | list_for_each_entry(lu, &tgt->lu_list, link) | 1190 | fw_device_enable_phys_dma(fw_parent_device(unit)); |
1181 | cancel_delayed_work_sync(&lu->work); | ||
1182 | |||
1183 | sbp2_release_target(tgt); | ||
1184 | 1191 | ||
1185 | return 0; | 1192 | /* |
1193 | * Fw-core serializes sbp2_update() against sbp2_remove(). | ||
1194 | * Iteration over tgt->lu_list is therefore safe here. | ||
1195 | */ | ||
1196 | list_for_each_entry(lu, &tgt->lu_list, link) { | ||
1197 | sbp2_conditionally_block(lu); | ||
1198 | lu->retries = 0; | ||
1199 | sbp2_queue_work(lu, 0); | ||
1200 | } | ||
1186 | } | 1201 | } |
1187 | 1202 | ||
1188 | static void sbp2_reconnect(struct work_struct *work) | 1203 | static void sbp2_release_target(struct sbp2_target *tgt) |
1189 | { | 1204 | { |
1190 | struct sbp2_logical_unit *lu = | 1205 | struct sbp2_logical_unit *lu, *next; |
1191 | container_of(work, struct sbp2_logical_unit, work.work); | 1206 | struct Scsi_Host *shost = |
1192 | struct sbp2_target *tgt = lu->tgt; | 1207 | container_of((void *)tgt, struct Scsi_Host, hostdata[0]); |
1208 | struct scsi_device *sdev; | ||
1193 | struct fw_device *device = target_device(tgt); | 1209 | struct fw_device *device = target_device(tgt); |
1194 | int generation, node_id, local_node_id; | ||
1195 | |||
1196 | if (fw_device_is_shutdown(device)) | ||
1197 | return; | ||
1198 | 1210 | ||
1199 | generation = device->generation; | 1211 | /* prevent deadlocks */ |
1200 | smp_rmb(); /* node IDs must not be older than generation */ | 1212 | sbp2_unblock(tgt); |
1201 | node_id = device->node_id; | ||
1202 | local_node_id = device->card->node_id; | ||
1203 | 1213 | ||
1204 | if (sbp2_send_management_orb(lu, node_id, generation, | 1214 | list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { |
1205 | SBP2_RECONNECT_REQUEST, | 1215 | sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun)); |
1206 | lu->login_id, NULL) < 0) { | 1216 | if (sdev) { |
1207 | /* | 1217 | scsi_remove_device(sdev); |
1208 | * If reconnect was impossible even though we are in the | 1218 | scsi_device_put(sdev); |
1209 | * current generation, fall back and try to log in again. | ||
1210 | * | ||
1211 | * We could check for "Function rejected" status, but | ||
1212 | * looking at the bus generation as simpler and more general. | ||
1213 | */ | ||
1214 | smp_rmb(); /* get current card generation */ | ||
1215 | if (generation == device->card->generation || | ||
1216 | lu->retries++ >= 5) { | ||
1217 | fw_error("%s: failed to reconnect\n", tgt->bus_id); | ||
1218 | lu->retries = 0; | ||
1219 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | ||
1220 | } | 1219 | } |
1221 | sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); | 1220 | if (lu->login_id != INVALID_LOGIN_ID) { |
1222 | 1221 | int generation, node_id; | |
1223 | return; | 1222 | /* |
1223 | * tgt->node_id may be obsolete here if we failed | ||
1224 | * during initial login or after a bus reset where | ||
1225 | * the topology changed. | ||
1226 | */ | ||
1227 | generation = device->generation; | ||
1228 | smp_rmb(); /* node_id vs. generation */ | ||
1229 | node_id = device->node_id; | ||
1230 | sbp2_send_management_orb(lu, node_id, generation, | ||
1231 | SBP2_LOGOUT_REQUEST, | ||
1232 | lu->login_id, NULL); | ||
1233 | } | ||
1234 | fw_core_remove_address_handler(&lu->address_handler); | ||
1235 | list_del(&lu->link); | ||
1236 | kfree(lu); | ||
1224 | } | 1237 | } |
1238 | scsi_remove_host(shost); | ||
1239 | fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no); | ||
1225 | 1240 | ||
1226 | tgt->node_id = node_id; | 1241 | scsi_host_put(shost); |
1227 | tgt->address_high = local_node_id << 16; | ||
1228 | smp_wmb(); /* node IDs must not be older than generation */ | ||
1229 | lu->generation = generation; | ||
1230 | |||
1231 | fw_notify("%s: reconnected to LUN %04x (%d retries)\n", | ||
1232 | tgt->bus_id, lu->lun, lu->retries); | ||
1233 | |||
1234 | sbp2_agent_reset(lu); | ||
1235 | sbp2_cancel_orbs(lu); | ||
1236 | sbp2_conditionally_unblock(lu); | ||
1237 | } | 1242 | } |
1238 | 1243 | ||
1239 | static void sbp2_update(struct fw_unit *unit) | 1244 | static int sbp2_remove(struct device *dev) |
1240 | { | 1245 | { |
1246 | struct fw_unit *unit = fw_unit(dev); | ||
1241 | struct sbp2_target *tgt = dev_get_drvdata(&unit->device); | 1247 | struct sbp2_target *tgt = dev_get_drvdata(&unit->device); |
1242 | struct sbp2_logical_unit *lu; | 1248 | struct sbp2_logical_unit *lu; |
1243 | 1249 | ||
1244 | fw_device_enable_phys_dma(fw_parent_device(unit)); | 1250 | list_for_each_entry(lu, &tgt->lu_list, link) |
1251 | cancel_delayed_work_sync(&lu->work); | ||
1245 | 1252 | ||
1246 | /* | 1253 | sbp2_release_target(tgt); |
1247 | * Fw-core serializes sbp2_update() against sbp2_remove(). | 1254 | |
1248 | * Iteration over tgt->lu_list is therefore safe here. | 1255 | return 0; |
1249 | */ | ||
1250 | list_for_each_entry(lu, &tgt->lu_list, link) { | ||
1251 | sbp2_conditionally_block(lu); | ||
1252 | lu->retries = 0; | ||
1253 | sbp2_queue_work(lu, 0); | ||
1254 | } | ||
1255 | } | 1256 | } |
1256 | 1257 | ||
1257 | #define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e | 1258 | #define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e |