diff options
| -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 |
