Commit b2af07b6844aade3a6d69511625bef2b1cb609cc
1 parent
6ff8147d07
Exists in
master
and in
6 other branches
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>
Showing 1 changed file with 107 additions and 106 deletions Side-by-side Diff
drivers/firewire/sbp2.c
... | ... | @@ -154,6 +154,11 @@ |
154 | 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 | 163 | * We create one struct sbp2_target per IEEE 1212 Unit Directory |
159 | 164 | * and one struct Scsi_Host per sbp2_target. |
... | ... | @@ -771,52 +776,6 @@ |
771 | 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 | 780 | * Write retransmit retry values into the BUSY_TIMEOUT register. |
822 | 781 | * - The single-phase retry protocol is supported by all SBP-2 devices, but the |
... | ... | @@ -955,6 +914,57 @@ |
955 | 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 | 968 | static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) |
959 | 969 | { |
960 | 970 | struct sbp2_logical_unit *lu; |
... | ... | @@ -1100,6 +1110,7 @@ |
1100 | 1110 | } |
1101 | 1111 | |
1102 | 1112 | static struct scsi_host_template scsi_driver_template; |
1113 | +static void sbp2_release_target(struct sbp2_target *tgt); | |
1103 | 1114 | |
1104 | 1115 | static int sbp2_probe(struct device *dev) |
1105 | 1116 | { |
1106 | 1117 | |
1107 | 1118 | |
1108 | 1119 | |
1109 | 1120 | |
1110 | 1121 | |
1111 | 1122 | |
1112 | 1123 | |
1113 | 1124 | |
1114 | 1125 | |
1115 | 1126 | |
1116 | 1127 | |
1117 | 1128 | |
1118 | 1129 | |
1119 | 1130 | |
1120 | 1131 | |
... | ... | @@ -1171,87 +1182,77 @@ |
1171 | 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 | 1187 | struct sbp2_target *tgt = dev_get_drvdata(&unit->device); |
1178 | 1188 | struct sbp2_logical_unit *lu; |
1179 | 1189 | |
1180 | - list_for_each_entry(lu, &tgt->lu_list, link) | |
1181 | - cancel_delayed_work_sync(&lu->work); | |
1190 | + fw_device_enable_phys_dma(fw_parent_device(unit)); | |
1182 | 1191 | |
1183 | - sbp2_release_target(tgt); | |
1184 | - | |
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 = | |
1191 | - container_of(work, struct sbp2_logical_unit, work.work); | |
1192 | - struct sbp2_target *tgt = lu->tgt; | |
1205 | + struct sbp2_logical_unit *lu, *next; | |
1206 | + struct Scsi_Host *shost = | |
1207 | + container_of((void *)tgt, struct Scsi_Host, hostdata[0]); | |
1208 | + struct scsi_device *sdev; | |
1193 | 1209 | struct fw_device *device = target_device(tgt); |
1194 | - int generation, node_id, local_node_id; | |
1195 | 1210 | |
1196 | - if (fw_device_is_shutdown(device)) | |
1197 | - return; | |
1211 | + /* prevent deadlocks */ | |
1212 | + sbp2_unblock(tgt); | |
1198 | 1213 | |
1199 | - generation = device->generation; | |
1200 | - smp_rmb(); /* node IDs must not be older than generation */ | |
1201 | - node_id = device->node_id; | |
1202 | - local_node_id = device->card->node_id; | |
1203 | - | |
1204 | - if (sbp2_send_management_orb(lu, node_id, generation, | |
1205 | - SBP2_RECONNECT_REQUEST, | |
1206 | - lu->login_id, NULL) < 0) { | |
1207 | - /* | |
1208 | - * If reconnect was impossible even though we are in the | |
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); | |
1214 | + list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { | |
1215 | + sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun)); | |
1216 | + if (sdev) { | |
1217 | + scsi_remove_device(sdev); | |
1218 | + scsi_device_put(sdev); | |
1220 | 1219 | } |
1221 | - sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); | |
1222 | - | |
1223 | - return; | |
1220 | + if (lu->login_id != INVALID_LOGIN_ID) { | |
1221 | + int generation, node_id; | |
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; | |
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); | |
1241 | + scsi_host_put(shost); | |
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 | 1247 | struct sbp2_target *tgt = dev_get_drvdata(&unit->device); |
1242 | 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 | - /* | |
1247 | - * Fw-core serializes sbp2_update() against sbp2_remove(). | |
1248 | - * Iteration over tgt->lu_list is therefore safe here. | |
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 | - } | |
1253 | + sbp2_release_target(tgt); | |
1254 | + | |
1255 | + return 0; | |
1255 | 1256 | } |
1256 | 1257 | |
1257 | 1258 | #define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e |