diff options
-rw-r--r-- | drivers/scsi/libiscsi.c | 54 | ||||
-rw-r--r-- | include/scsi/libiscsi.h | 7 |
2 files changed, 50 insertions, 11 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index f5915d4d63d9..efceed451b46 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -1056,7 +1056,9 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1056 | ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, | 1056 | ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, |
1057 | NULL, 0); | 1057 | NULL, 0); |
1058 | if (!ctask->mtask) { | 1058 | if (!ctask->mtask) { |
1059 | spin_unlock_bh(&session->lock); | ||
1059 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1060 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1061 | spin_lock_bh(&session->lock) | ||
1060 | debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); | 1062 | debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); |
1061 | return -EPERM; | 1063 | return -EPERM; |
1062 | } | 1064 | } |
@@ -1073,6 +1075,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1073 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); | 1075 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); |
1074 | } | 1076 | } |
1075 | spin_unlock_bh(&session->lock); | 1077 | spin_unlock_bh(&session->lock); |
1078 | mutex_unlock(&session->eh_mutex); | ||
1076 | scsi_queue_work(session->host, &conn->xmitwork); | 1079 | scsi_queue_work(session->host, &conn->xmitwork); |
1077 | 1080 | ||
1078 | /* | 1081 | /* |
@@ -1090,6 +1093,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1090 | if (signal_pending(current)) | 1093 | if (signal_pending(current)) |
1091 | flush_signals(current); | 1094 | flush_signals(current); |
1092 | del_timer_sync(&conn->tmabort_timer); | 1095 | del_timer_sync(&conn->tmabort_timer); |
1096 | mutex_lock(&session->eh_mutex); | ||
1093 | spin_lock_bh(&session->lock); | 1097 | spin_lock_bh(&session->lock); |
1094 | return 0; | 1098 | return 0; |
1095 | } | 1099 | } |
@@ -1165,31 +1169,45 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1165 | __iscsi_put_ctask(ctask); | 1169 | __iscsi_put_ctask(ctask); |
1166 | } | 1170 | } |
1167 | 1171 | ||
1172 | static void iscsi_suspend_tx(struct iscsi_conn *conn) | ||
1173 | { | ||
1174 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1175 | scsi_flush_work(conn->session->host); | ||
1176 | } | ||
1177 | |||
1178 | static void iscsi_start_tx(struct iscsi_conn *conn) | ||
1179 | { | ||
1180 | clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1181 | scsi_queue_work(conn->session->host, &conn->xmitwork); | ||
1182 | } | ||
1183 | |||
1168 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1184 | int iscsi_eh_abort(struct scsi_cmnd *sc) |
1169 | { | 1185 | { |
1186 | struct Scsi_Host *host = sc->device->host; | ||
1187 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | ||
1170 | struct iscsi_cmd_task *ctask; | 1188 | struct iscsi_cmd_task *ctask; |
1171 | struct iscsi_conn *conn; | 1189 | struct iscsi_conn *conn; |
1172 | struct iscsi_session *session; | ||
1173 | int rc; | 1190 | int rc; |
1174 | 1191 | ||
1192 | mutex_lock(&session->eh_mutex); | ||
1193 | spin_lock_bh(&session->lock); | ||
1175 | /* | 1194 | /* |
1176 | * if session was ISCSI_STATE_IN_RECOVERY then we may not have | 1195 | * if session was ISCSI_STATE_IN_RECOVERY then we may not have |
1177 | * got the command. | 1196 | * got the command. |
1178 | */ | 1197 | */ |
1179 | if (!sc->SCp.ptr) { | 1198 | if (!sc->SCp.ptr) { |
1180 | debug_scsi("sc never reached iscsi layer or it completed.\n"); | 1199 | debug_scsi("sc never reached iscsi layer or it completed.\n"); |
1200 | spin_unlock_bh(&session->lock); | ||
1201 | mutex_unlock(&session->eh_mutex); | ||
1181 | return SUCCESS; | 1202 | return SUCCESS; |
1182 | } | 1203 | } |
1183 | 1204 | ||
1184 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | 1205 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; |
1185 | conn = ctask->conn; | 1206 | conn = ctask->conn; |
1186 | session = conn->session; | ||
1187 | 1207 | ||
1188 | conn->eh_abort_cnt++; | 1208 | conn->eh_abort_cnt++; |
1189 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | 1209 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); |
1190 | 1210 | ||
1191 | spin_lock_bh(&session->lock); | ||
1192 | |||
1193 | /* | 1211 | /* |
1194 | * If we are not logged in or we have started a new session | 1212 | * If we are not logged in or we have started a new session |
1195 | * then let the host reset code handle this | 1213 | * then let the host reset code handle this |
@@ -1226,6 +1244,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1226 | switch (conn->tmabort_state) { | 1244 | switch (conn->tmabort_state) { |
1227 | case TMABORT_SUCCESS: | 1245 | case TMABORT_SUCCESS: |
1228 | spin_unlock_bh(&session->lock); | 1246 | spin_unlock_bh(&session->lock); |
1247 | iscsi_suspend_tx(conn); | ||
1229 | /* | 1248 | /* |
1230 | * clean up task if aborted. grab the recv lock as a writer | 1249 | * clean up task if aborted. grab the recv lock as a writer |
1231 | */ | 1250 | */ |
@@ -1234,11 +1253,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1234 | fail_command(conn, ctask, DID_ABORT << 16); | 1253 | fail_command(conn, ctask, DID_ABORT << 16); |
1235 | spin_unlock(&session->lock); | 1254 | spin_unlock(&session->lock); |
1236 | write_unlock_bh(conn->recv_lock); | 1255 | write_unlock_bh(conn->recv_lock); |
1237 | /* | 1256 | iscsi_start_tx(conn); |
1238 | * make sure xmit thread is not still touching the | ||
1239 | * ctask/scsi_cmnd | ||
1240 | */ | ||
1241 | scsi_flush_work(session->host); | ||
1242 | goto success_unlocked; | 1257 | goto success_unlocked; |
1243 | case TMABORT_NOT_FOUND: | 1258 | case TMABORT_NOT_FOUND: |
1244 | if (!ctask->sc) { | 1259 | if (!ctask->sc) { |
@@ -1258,12 +1273,14 @@ success: | |||
1258 | spin_unlock_bh(&session->lock); | 1273 | spin_unlock_bh(&session->lock); |
1259 | success_unlocked: | 1274 | success_unlocked: |
1260 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1275 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
1276 | mutex_unlock(&session->eh_mutex); | ||
1261 | return SUCCESS; | 1277 | return SUCCESS; |
1262 | 1278 | ||
1263 | failed: | 1279 | failed: |
1264 | spin_unlock_bh(&session->lock); | 1280 | spin_unlock_bh(&session->lock); |
1265 | failed_unlocked: | 1281 | failed_unlocked: |
1266 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1282 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
1283 | mutex_unlock(&session->eh_mutex); | ||
1267 | return FAILED; | 1284 | return FAILED; |
1268 | } | 1285 | } |
1269 | EXPORT_SYMBOL_GPL(iscsi_eh_abort); | 1286 | EXPORT_SYMBOL_GPL(iscsi_eh_abort); |
@@ -1410,6 +1427,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1410 | session->max_cmdsn = initial_cmdsn + 1; | 1427 | session->max_cmdsn = initial_cmdsn + 1; |
1411 | session->max_r2t = 1; | 1428 | session->max_r2t = 1; |
1412 | session->tt = iscsit; | 1429 | session->tt = iscsit; |
1430 | mutex_init(&session->eh_mutex); | ||
1413 | 1431 | ||
1414 | /* initialize SCSI PDU commands pool */ | 1432 | /* initialize SCSI PDU commands pool */ |
1415 | if (iscsi_pool_init(&session->cmdpool, session->cmds_max, | 1433 | if (iscsi_pool_init(&session->cmdpool, session->cmds_max, |
@@ -1743,9 +1761,22 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1743 | { | 1761 | { |
1744 | int old_stop_stage; | 1762 | int old_stop_stage; |
1745 | 1763 | ||
1764 | mutex_lock(&session->eh_mutex); | ||
1746 | spin_lock_bh(&session->lock); | 1765 | spin_lock_bh(&session->lock); |
1747 | if (conn->stop_stage == STOP_CONN_TERM) { | 1766 | if (conn->stop_stage == STOP_CONN_TERM) { |
1748 | spin_unlock_bh(&session->lock); | 1767 | spin_unlock_bh(&session->lock); |
1768 | mutex_unlock(&session->eh_mutex); | ||
1769 | return; | ||
1770 | } | ||
1771 | |||
1772 | /* | ||
1773 | * The LLD either freed/unset the lock on us, or userspace called | ||
1774 | * stop but did not create a proper connection (connection was never | ||
1775 | * bound or it was unbound then stop was called). | ||
1776 | */ | ||
1777 | if (!conn->recv_lock) { | ||
1778 | spin_unlock_bh(&session->lock); | ||
1779 | mutex_unlock(&session->eh_mutex); | ||
1749 | return; | 1780 | return; |
1750 | } | 1781 | } |
1751 | 1782 | ||
@@ -1762,9 +1793,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1762 | old_stop_stage = conn->stop_stage; | 1793 | old_stop_stage = conn->stop_stage; |
1763 | conn->stop_stage = flag; | 1794 | conn->stop_stage = flag; |
1764 | conn->c_stage = ISCSI_CONN_STOPPED; | 1795 | conn->c_stage = ISCSI_CONN_STOPPED; |
1765 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1766 | spin_unlock_bh(&session->lock); | 1796 | spin_unlock_bh(&session->lock); |
1767 | scsi_flush_work(session->host); | 1797 | |
1798 | iscsi_suspend_tx(conn); | ||
1768 | 1799 | ||
1769 | write_lock_bh(conn->recv_lock); | 1800 | write_lock_bh(conn->recv_lock); |
1770 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); | 1801 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); |
@@ -1793,6 +1824,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1793 | fail_all_commands(conn); | 1824 | fail_all_commands(conn); |
1794 | flush_control_queues(session, conn); | 1825 | flush_control_queues(session, conn); |
1795 | spin_unlock_bh(&session->lock); | 1826 | spin_unlock_bh(&session->lock); |
1827 | mutex_unlock(&session->eh_mutex); | ||
1796 | } | 1828 | } |
1797 | 1829 | ||
1798 | void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 1830 | void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 007d442412e2..b4b31132618b 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h | |||
@@ -205,6 +205,13 @@ struct iscsi_queue { | |||
205 | }; | 205 | }; |
206 | 206 | ||
207 | struct iscsi_session { | 207 | struct iscsi_session { |
208 | /* | ||
209 | * Syncs up the scsi eh thread with the iscsi eh thread when sending | ||
210 | * task management functions. This must be taken before the session | ||
211 | * and recv lock. | ||
212 | */ | ||
213 | struct mutex eh_mutex; | ||
214 | |||
208 | /* iSCSI session-wide sequencing */ | 215 | /* iSCSI session-wide sequencing */ |
209 | uint32_t cmdsn; | 216 | uint32_t cmdsn; |
210 | uint32_t exp_cmdsn; | 217 | uint32_t exp_cmdsn; |