aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2009-11-11 17:34:32 -0500
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:01:36 -0500
commit5d12c05e29fc8715e3e32f57a8cced9290d87c55 (patch)
treee73691cdb5a2a52a9b56ad9f06183f49bb4e3d49
parent4f704dc03297406ea5d53b85c4666c60f69000bf (diff)
[SCSI] libiscsi: Check TMF state before sending PDU
Patch and mail from both MikeC and HannesR: Before we're trying to send a PDU we have to check whether a TMF is active. If so and if the PDU will be affected by the TMF we should allow only Data-out PDUs to be sent. If fast_abort is set, no Data-out PDUs will be sent while a LUN reset is being processed for a affected LUN. fast_abort is now ingored during a ABORT TASK tmf. We will not send any Data-outs for a task if the task is being aborted. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/libiscsi.c113
-rw-r--r--include/scsi/iscsi_proto.h2
2 files changed, 103 insertions, 12 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8c29480fc02b..b6ffdc5512cd 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -266,6 +266,88 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
266} 266}
267 267
268/** 268/**
269 * iscsi_check_tmf_restrictions - check if a task is affected by TMF
270 * @task: iscsi task
271 * @opcode: opcode to check for
272 *
273 * During TMF a task has to be checked if it's affected.
274 * All unrelated I/O can be passed through, but I/O to the
275 * affected LUN should be restricted.
276 * If 'fast_abort' is set we won't be sending any I/O to the
277 * affected LUN.
278 * Otherwise the target is waiting for all TTTs to be completed,
279 * so we have to send all outstanding Data-Out PDUs to the target.
280 */
281static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
282{
283 struct iscsi_conn *conn = task->conn;
284 struct iscsi_tm *tmf = &conn->tmhdr;
285 unsigned int hdr_lun;
286
287 if (conn->tmf_state == TMF_INITIAL)
288 return 0;
289
290 if ((tmf->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_TMFUNC)
291 return 0;
292
293 switch (ISCSI_TM_FUNC_VALUE(tmf)) {
294 case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
295 /*
296 * Allow PDUs for unrelated LUNs
297 */
298 hdr_lun = scsilun_to_int((struct scsi_lun *)tmf->lun);
299 if (hdr_lun != task->sc->device->lun)
300 return 0;
301
302 /*
303 * Fail all SCSI cmd PDUs
304 */
305 if (opcode != ISCSI_OP_SCSI_DATA_OUT) {
306 iscsi_conn_printk(KERN_INFO, conn,
307 "task [op %x/%x itt "
308 "0x%x/0x%x lun %u] "
309 "rejected.\n",
310 task->hdr->opcode, opcode,
311 task->itt, task->hdr_itt, hdr_lun);
312 return -EACCES;
313 }
314 /*
315 * And also all data-out PDUs in response to R2T
316 * if fast_abort is set.
317 */
318 if (conn->session->fast_abort) {
319 iscsi_conn_printk(KERN_INFO, conn,
320 "task [op %x/%x itt "
321 "0x%x/0x%x lun %u] "
322 "fast abort.\n",
323 task->hdr->opcode, opcode,
324 task->itt, task->hdr_itt, hdr_lun);
325 return -EACCES;
326 }
327 break;
328 case ISCSI_TM_FUNC_ABORT_TASK:
329 /*
330 * the caller has already checked if the task
331 * they want to abort was in the pending queue so if
332 * we are here the cmd pdu has gone out already, and
333 * we will only hit this for data-outs
334 */
335 if (opcode == ISCSI_OP_SCSI_DATA_OUT &&
336 task->hdr_itt == tmf->rtt) {
337 ISCSI_DBG_SESSION(conn->session,
338 "Preventing task %x/%x from sending "
339 "data-out due to abort task in "
340 "progress\n", task->itt,
341 task->hdr_itt);
342 return -EACCES;
343 }
344 break;
345 }
346
347 return 0;
348}
349
350/**
269 * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu 351 * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
270 * @task: iscsi task 352 * @task: iscsi task
271 * 353 *
@@ -282,6 +364,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
282 itt_t itt; 364 itt_t itt;
283 int rc; 365 int rc;
284 366
367 rc = iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_CMD);
368 if (rc)
369 return rc;
370
285 if (conn->session->tt->alloc_pdu) { 371 if (conn->session->tt->alloc_pdu) {
286 rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD); 372 rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
287 if (rc) 373 if (rc)
@@ -1366,6 +1452,7 @@ EXPORT_SYMBOL_GPL(iscsi_requeue_task);
1366 **/ 1452 **/
1367static int iscsi_data_xmit(struct iscsi_conn *conn) 1453static int iscsi_data_xmit(struct iscsi_conn *conn)
1368{ 1454{
1455 struct iscsi_task *task;
1369 int rc = 0; 1456 int rc = 0;
1370 1457
1371 spin_lock_bh(&conn->session->lock); 1458 spin_lock_bh(&conn->session->lock);
@@ -1403,11 +1490,8 @@ check_mgmt:
1403 1490
1404 /* process pending command queue */ 1491 /* process pending command queue */
1405 while (!list_empty(&conn->cmdqueue)) { 1492 while (!list_empty(&conn->cmdqueue)) {
1406 if (conn->tmf_state == TMF_QUEUED) 1493 conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task,
1407 break; 1494 running);
1408
1409 conn->task = list_entry(conn->cmdqueue.next,
1410 struct iscsi_task, running);
1411 list_del_init(&conn->task->running); 1495 list_del_init(&conn->task->running);
1412 if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { 1496 if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
1413 fail_scsi_task(conn->task, DID_IMM_RETRY); 1497 fail_scsi_task(conn->task, DID_IMM_RETRY);
@@ -1415,7 +1499,7 @@ check_mgmt:
1415 } 1499 }
1416 rc = iscsi_prep_scsi_cmd_pdu(conn->task); 1500 rc = iscsi_prep_scsi_cmd_pdu(conn->task);
1417 if (rc) { 1501 if (rc) {
1418 if (rc == -ENOMEM) { 1502 if (rc == -ENOMEM || rc == -EACCES) {
1419 list_add_tail(&conn->task->running, 1503 list_add_tail(&conn->task->running,
1420 &conn->cmdqueue); 1504 &conn->cmdqueue);
1421 conn->task = NULL; 1505 conn->task = NULL;
@@ -1437,17 +1521,18 @@ check_mgmt:
1437 } 1521 }
1438 1522
1439 while (!list_empty(&conn->requeue)) { 1523 while (!list_empty(&conn->requeue)) {
1440 if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
1441 break;
1442
1443 /* 1524 /*
1444 * we always do fastlogout - conn stop code will clean up. 1525 * we always do fastlogout - conn stop code will clean up.
1445 */ 1526 */
1446 if (conn->session->state == ISCSI_STATE_LOGGING_OUT) 1527 if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
1447 break; 1528 break;
1448 1529
1449 conn->task = list_entry(conn->requeue.next, 1530 task = list_entry(conn->requeue.next, struct iscsi_task,
1450 struct iscsi_task, running); 1531 running);
1532 if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
1533 break;
1534
1535 conn->task = task;
1451 list_del_init(&conn->task->running); 1536 list_del_init(&conn->task->running);
1452 conn->task->state = ISCSI_TASK_RUNNING; 1537 conn->task->state = ISCSI_TASK_RUNNING;
1453 rc = iscsi_xmit_task(conn); 1538 rc = iscsi_xmit_task(conn);
@@ -1600,7 +1685,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
1600 if (!ihost->workq) { 1685 if (!ihost->workq) {
1601 reason = iscsi_prep_scsi_cmd_pdu(task); 1686 reason = iscsi_prep_scsi_cmd_pdu(task);
1602 if (reason) { 1687 if (reason) {
1603 if (reason == -ENOMEM) { 1688 if (reason == -ENOMEM || reason == -EACCES) {
1604 reason = FAILURE_OOM; 1689 reason = FAILURE_OOM;
1605 goto prepd_reject; 1690 goto prepd_reject;
1606 } else { 1691 } else {
@@ -2120,6 +2205,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
2120 spin_lock_bh(&session->lock); 2205 spin_lock_bh(&session->lock);
2121 fail_scsi_task(task, DID_ABORT); 2206 fail_scsi_task(task, DID_ABORT);
2122 conn->tmf_state = TMF_INITIAL; 2207 conn->tmf_state = TMF_INITIAL;
2208 memset(hdr, 0, sizeof(*hdr));
2123 spin_unlock_bh(&session->lock); 2209 spin_unlock_bh(&session->lock);
2124 iscsi_start_tx(conn); 2210 iscsi_start_tx(conn);
2125 goto success_unlocked; 2211 goto success_unlocked;
@@ -2130,6 +2216,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
2130 case TMF_NOT_FOUND: 2216 case TMF_NOT_FOUND:
2131 if (!sc->SCp.ptr) { 2217 if (!sc->SCp.ptr) {
2132 conn->tmf_state = TMF_INITIAL; 2218 conn->tmf_state = TMF_INITIAL;
2219 memset(hdr, 0, sizeof(*hdr));
2133 /* task completed before tmf abort response */ 2220 /* task completed before tmf abort response */
2134 ISCSI_DBG_EH(session, "sc completed while abort in " 2221 ISCSI_DBG_EH(session, "sc completed while abort in "
2135 "progress\n"); 2222 "progress\n");
@@ -2224,6 +2311,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
2224 iscsi_suspend_tx(conn); 2311 iscsi_suspend_tx(conn);
2225 2312
2226 spin_lock_bh(&session->lock); 2313 spin_lock_bh(&session->lock);
2314 memset(hdr, 0, sizeof(*hdr));
2227 fail_scsi_tasks(conn, sc->device->lun, DID_ERROR); 2315 fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
2228 conn->tmf_state = TMF_INITIAL; 2316 conn->tmf_state = TMF_INITIAL;
2229 spin_unlock_bh(&session->lock); 2317 spin_unlock_bh(&session->lock);
@@ -2868,6 +2956,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
2868 spin_lock_bh(&session->lock); 2956 spin_lock_bh(&session->lock);
2869 fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED); 2957 fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
2870 fail_mgmt_tasks(session, conn); 2958 fail_mgmt_tasks(session, conn);
2959 memset(&conn->tmhdr, 0, sizeof(conn->tmhdr));
2871 spin_unlock_bh(&session->lock); 2960 spin_unlock_bh(&session->lock);
2872 mutex_unlock(&session->eh_mutex); 2961 mutex_unlock(&session->eh_mutex);
2873} 2962}
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index f2a2c1169486..dd0a52cea95a 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -279,6 +279,8 @@ struct iscsi_tm {
279#define ISCSI_TM_FUNC_TARGET_COLD_RESET 7 279#define ISCSI_TM_FUNC_TARGET_COLD_RESET 7
280#define ISCSI_TM_FUNC_TASK_REASSIGN 8 280#define ISCSI_TM_FUNC_TASK_REASSIGN 8
281 281
282#define ISCSI_TM_FUNC_VALUE(hdr) ((hdr)->flags & ISCSI_FLAG_TM_FUNC_MASK)
283
282/* SCSI Task Management Response Header */ 284/* SCSI Task Management Response Header */
283struct iscsi_tm_rsp { 285struct iscsi_tm_rsp {
284 uint8_t opcode; 286 uint8_t opcode;