diff options
author | David Dillow <dillowda@ornl.gov> | 2010-11-26 13:02:21 -0500 |
---|---|---|
committer | David Dillow <dillowda@ornl.gov> | 2011-01-05 15:24:25 -0500 |
commit | f8b6e31e4e46bf514c27fce38783ed5615cca01d (patch) | |
tree | 0ae9afcb65749e36034b6de03abe5fd51c5dc7b0 /drivers/infiniband | |
parent | 3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 (diff) |
IB/srp: allow task management without a previous request
We can only have one task management comment outstanding, so move the
completion and status to the target port. This allows us to handle
resets of a LUN without a corresponding request having been sent.
Meanwhile, we don't need to play games with host_scribble, just use it
as the pointer it is.
This fixes a crash when we issue a bus reset using sg_reset.
Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=13893
Reported-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: David Dillow <dillowda@ornl.gov>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 90 | ||||
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.h | 10 |
2 files changed, 37 insertions, 63 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 1e1e347a7715..29429a13fd90 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
@@ -542,6 +542,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, | |||
542 | static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) | 542 | static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) |
543 | { | 543 | { |
544 | srp_unmap_data(req->scmnd, target, req); | 544 | srp_unmap_data(req->scmnd, target, req); |
545 | req->scmnd = NULL; | ||
545 | list_move_tail(&req->list, &target->free_reqs); | 546 | list_move_tail(&req->list, &target->free_reqs); |
546 | } | 547 | } |
547 | 548 | ||
@@ -925,15 +926,13 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | |||
925 | 926 | ||
926 | target->req_lim += delta; | 927 | target->req_lim += delta; |
927 | 928 | ||
928 | req = &target->req_ring[rsp->tag & ~SRP_TAG_TSK_MGMT]; | ||
929 | |||
930 | if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { | 929 | if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { |
931 | if (be32_to_cpu(rsp->resp_data_len) < 4) | 930 | target->tsk_mgmt_status = -1; |
932 | req->tsk_status = -1; | 931 | if (be32_to_cpu(rsp->resp_data_len) >= 4) |
933 | else | 932 | target->tsk_mgmt_status = rsp->data[3]; |
934 | req->tsk_status = rsp->data[3]; | 933 | complete(&target->tsk_mgmt_done); |
935 | complete(&req->done); | ||
936 | } else { | 934 | } else { |
935 | req = &target->req_ring[rsp->tag]; | ||
937 | scmnd = req->scmnd; | 936 | scmnd = req->scmnd; |
938 | if (!scmnd) | 937 | if (!scmnd) |
939 | shost_printk(KERN_ERR, target->scsi_host, | 938 | shost_printk(KERN_ERR, target->scsi_host, |
@@ -953,13 +952,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | |||
953 | else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) | 952 | else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) |
954 | scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); | 953 | scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); |
955 | 954 | ||
956 | if (!req->tsk_mgmt) { | 955 | scmnd->host_scribble = NULL; |
957 | scmnd->host_scribble = (void *) -1L; | 956 | scmnd->scsi_done(scmnd); |
958 | scmnd->scsi_done(scmnd); | 957 | srp_remove_req(target, req); |
959 | |||
960 | srp_remove_req(target, req); | ||
961 | } else | ||
962 | req->cmd_done = 1; | ||
963 | } | 958 | } |
964 | 959 | ||
965 | spin_unlock_irqrestore(target->scsi_host->host_lock, flags); | 960 | spin_unlock_irqrestore(target->scsi_host->host_lock, flags); |
@@ -1155,7 +1150,7 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, | |||
1155 | 1150 | ||
1156 | scmnd->scsi_done = done; | 1151 | scmnd->scsi_done = done; |
1157 | scmnd->result = 0; | 1152 | scmnd->result = 0; |
1158 | scmnd->host_scribble = (void *) (long) req->index; | 1153 | scmnd->host_scribble = (void *) req; |
1159 | 1154 | ||
1160 | cmd = iu->buf; | 1155 | cmd = iu->buf; |
1161 | memset(cmd, 0, sizeof *cmd); | 1156 | memset(cmd, 0, sizeof *cmd); |
@@ -1167,8 +1162,6 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, | |||
1167 | 1162 | ||
1168 | req->scmnd = scmnd; | 1163 | req->scmnd = scmnd; |
1169 | req->cmd = iu; | 1164 | req->cmd = iu; |
1170 | req->cmd_done = 0; | ||
1171 | req->tsk_mgmt = NULL; | ||
1172 | 1165 | ||
1173 | len = srp_map_data(scmnd, target, req); | 1166 | len = srp_map_data(scmnd, target, req); |
1174 | if (len < 0) { | 1167 | if (len < 0) { |
@@ -1442,7 +1435,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) | |||
1442 | } | 1435 | } |
1443 | 1436 | ||
1444 | static int srp_send_tsk_mgmt(struct srp_target_port *target, | 1437 | static int srp_send_tsk_mgmt(struct srp_target_port *target, |
1445 | struct srp_request *req, u8 func) | 1438 | u64 req_tag, unsigned int lun, u8 func) |
1446 | { | 1439 | { |
1447 | struct ib_device *dev = target->srp_host->srp_dev->dev; | 1440 | struct ib_device *dev = target->srp_host->srp_dev->dev; |
1448 | struct srp_iu *iu; | 1441 | struct srp_iu *iu; |
@@ -1451,12 +1444,10 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, | |||
1451 | spin_lock_irq(target->scsi_host->host_lock); | 1444 | spin_lock_irq(target->scsi_host->host_lock); |
1452 | 1445 | ||
1453 | if (target->state == SRP_TARGET_DEAD || | 1446 | if (target->state == SRP_TARGET_DEAD || |
1454 | target->state == SRP_TARGET_REMOVED) { | 1447 | target->state == SRP_TARGET_REMOVED) |
1455 | req->scmnd->result = DID_BAD_TARGET << 16; | ||
1456 | goto out; | 1448 | goto out; |
1457 | } | ||
1458 | 1449 | ||
1459 | init_completion(&req->done); | 1450 | init_completion(&target->tsk_mgmt_done); |
1460 | 1451 | ||
1461 | iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); | 1452 | iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); |
1462 | if (!iu) | 1453 | if (!iu) |
@@ -1468,21 +1459,19 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, | |||
1468 | memset(tsk_mgmt, 0, sizeof *tsk_mgmt); | 1459 | memset(tsk_mgmt, 0, sizeof *tsk_mgmt); |
1469 | 1460 | ||
1470 | tsk_mgmt->opcode = SRP_TSK_MGMT; | 1461 | tsk_mgmt->opcode = SRP_TSK_MGMT; |
1471 | tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48); | 1462 | tsk_mgmt->lun = cpu_to_be64((u64) lun << 48); |
1472 | tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT; | 1463 | tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT; |
1473 | tsk_mgmt->tsk_mgmt_func = func; | 1464 | tsk_mgmt->tsk_mgmt_func = func; |
1474 | tsk_mgmt->task_tag = req->index; | 1465 | tsk_mgmt->task_tag = req_tag; |
1475 | 1466 | ||
1476 | ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, | 1467 | ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, |
1477 | DMA_TO_DEVICE); | 1468 | DMA_TO_DEVICE); |
1478 | if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) | 1469 | if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) |
1479 | goto out; | 1470 | goto out; |
1480 | 1471 | ||
1481 | req->tsk_mgmt = iu; | ||
1482 | |||
1483 | spin_unlock_irq(target->scsi_host->host_lock); | 1472 | spin_unlock_irq(target->scsi_host->host_lock); |
1484 | 1473 | ||
1485 | if (!wait_for_completion_timeout(&req->done, | 1474 | if (!wait_for_completion_timeout(&target->tsk_mgmt_done, |
1486 | msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) | 1475 | msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) |
1487 | return -1; | 1476 | return -1; |
1488 | 1477 | ||
@@ -1493,43 +1482,29 @@ out: | |||
1493 | return -1; | 1482 | return -1; |
1494 | } | 1483 | } |
1495 | 1484 | ||
1496 | static int srp_find_req(struct srp_target_port *target, | ||
1497 | struct scsi_cmnd *scmnd, | ||
1498 | struct srp_request **req) | ||
1499 | { | ||
1500 | if (scmnd->host_scribble == (void *) -1L) | ||
1501 | return -1; | ||
1502 | |||
1503 | *req = &target->req_ring[(long) scmnd->host_scribble]; | ||
1504 | |||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1508 | static int srp_abort(struct scsi_cmnd *scmnd) | 1485 | static int srp_abort(struct scsi_cmnd *scmnd) |
1509 | { | 1486 | { |
1510 | struct srp_target_port *target = host_to_target(scmnd->device->host); | 1487 | struct srp_target_port *target = host_to_target(scmnd->device->host); |
1511 | struct srp_request *req; | 1488 | struct srp_request *req = (struct srp_request *) scmnd->host_scribble; |
1512 | int ret = SUCCESS; | 1489 | int ret = SUCCESS; |
1513 | 1490 | ||
1514 | shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); | 1491 | shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); |
1515 | 1492 | ||
1516 | if (target->qp_in_error) | 1493 | if (!req || target->qp_in_error) |
1517 | return FAILED; | ||
1518 | if (srp_find_req(target, scmnd, &req)) | ||
1519 | return FAILED; | 1494 | return FAILED; |
1520 | if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) | 1495 | if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, |
1496 | SRP_TSK_ABORT_TASK)) | ||
1521 | return FAILED; | 1497 | return FAILED; |
1522 | 1498 | ||
1523 | spin_lock_irq(target->scsi_host->host_lock); | 1499 | spin_lock_irq(target->scsi_host->host_lock); |
1524 | 1500 | ||
1525 | if (req->cmd_done) { | 1501 | if (req->scmnd) { |
1526 | srp_remove_req(target, req); | 1502 | if (!target->tsk_mgmt_status) { |
1527 | scmnd->scsi_done(scmnd); | 1503 | srp_remove_req(target, req); |
1528 | } else if (!req->tsk_status) { | 1504 | scmnd->result = DID_ABORT << 16; |
1529 | srp_remove_req(target, req); | 1505 | } else |
1530 | scmnd->result = DID_ABORT << 16; | 1506 | ret = FAILED; |
1531 | } else | 1507 | } |
1532 | ret = FAILED; | ||
1533 | 1508 | ||
1534 | spin_unlock_irq(target->scsi_host->host_lock); | 1509 | spin_unlock_irq(target->scsi_host->host_lock); |
1535 | 1510 | ||
@@ -1545,17 +1520,16 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) | |||
1545 | 1520 | ||
1546 | if (target->qp_in_error) | 1521 | if (target->qp_in_error) |
1547 | return FAILED; | 1522 | return FAILED; |
1548 | if (srp_find_req(target, scmnd, &req)) | 1523 | if (srp_send_tsk_mgmt(target, SRP_TAG_NO_REQ, scmnd->device->lun, |
1549 | return FAILED; | 1524 | SRP_TSK_LUN_RESET)) |
1550 | if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) | ||
1551 | return FAILED; | 1525 | return FAILED; |
1552 | if (req->tsk_status) | 1526 | if (target->tsk_mgmt_status) |
1553 | return FAILED; | 1527 | return FAILED; |
1554 | 1528 | ||
1555 | spin_lock_irq(target->scsi_host->host_lock); | 1529 | spin_lock_irq(target->scsi_host->host_lock); |
1556 | 1530 | ||
1557 | list_for_each_entry_safe(req, tmp, &target->req_queue, list) | 1531 | list_for_each_entry_safe(req, tmp, &target->req_queue, list) |
1558 | if (req->scmnd->device == scmnd->device) | 1532 | if (req->scmnd && req->scmnd->device == scmnd->device) |
1559 | srp_reset_req(target, req); | 1533 | srp_reset_req(target, req); |
1560 | 1534 | ||
1561 | spin_unlock_irq(target->scsi_host->host_lock); | 1535 | spin_unlock_irq(target->scsi_host->host_lock); |
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index ed0dce9e479f..f8b689a644b7 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h | |||
@@ -68,7 +68,8 @@ enum { | |||
68 | SRP_TSK_MGMT_SQ_SIZE = 1, | 68 | SRP_TSK_MGMT_SQ_SIZE = 1, |
69 | SRP_CMD_SQ_SIZE = SRP_REQ_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE, | 69 | SRP_CMD_SQ_SIZE = SRP_REQ_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE, |
70 | 70 | ||
71 | SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1), | 71 | SRP_TAG_NO_REQ = ~0U, |
72 | SRP_TAG_TSK_MGMT = 1U << 31, | ||
72 | 73 | ||
73 | SRP_FMR_SIZE = 256, | 74 | SRP_FMR_SIZE = 256, |
74 | SRP_FMR_POOL_SIZE = 1024, | 75 | SRP_FMR_POOL_SIZE = 1024, |
@@ -113,12 +114,8 @@ struct srp_request { | |||
113 | struct list_head list; | 114 | struct list_head list; |
114 | struct scsi_cmnd *scmnd; | 115 | struct scsi_cmnd *scmnd; |
115 | struct srp_iu *cmd; | 116 | struct srp_iu *cmd; |
116 | struct srp_iu *tsk_mgmt; | ||
117 | struct ib_pool_fmr *fmr; | 117 | struct ib_pool_fmr *fmr; |
118 | struct completion done; | ||
119 | short index; | 118 | short index; |
120 | u8 cmd_done; | ||
121 | u8 tsk_status; | ||
122 | }; | 119 | }; |
123 | 120 | ||
124 | struct srp_target_port { | 121 | struct srp_target_port { |
@@ -165,6 +162,9 @@ struct srp_target_port { | |||
165 | int status; | 162 | int status; |
166 | enum srp_target_state state; | 163 | enum srp_target_state state; |
167 | int qp_in_error; | 164 | int qp_in_error; |
165 | |||
166 | struct completion tsk_mgmt_done; | ||
167 | u8 tsk_mgmt_status; | ||
168 | }; | 168 | }; |
169 | 169 | ||
170 | struct srp_iu { | 170 | struct srp_iu { |