aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2010-04-20 15:21:33 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-05-02 11:03:03 -0400
commitf5832fa2f8dc39adcf3ae348d2d6383163235e79 (patch)
tree1fea25c52248b213dd44d2ad693959ff29d56495
parent859e816704b4139d15b1ec6a3505f12faef5333a (diff)
[SCSI] ibmvfc: Fix command completion handling
Commands which are completed by the VIOS are placed on a CRQ in kernel memory for the ibmvfc driver to process. Each CRQ entry is 16 bytes. The ibmvfc driver reads the first 8 bytes to check if the entry is valid, then reads the next 8 bytes to get the handle, which is a pointer the completed command. This fixes an issue seen on Power 7 where the processor reordered the loads from memory, resulting in processing command completion with a stale handle. This could result in command timeouts, and also early completion of commands. Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index c2eea711a5ce..9372169374e2 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -3013,6 +3013,7 @@ static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost)
3013 if (crq->valid & 0x80) { 3013 if (crq->valid & 0x80) {
3014 if (++async_crq->cur == async_crq->size) 3014 if (++async_crq->cur == async_crq->size)
3015 async_crq->cur = 0; 3015 async_crq->cur = 0;
3016 rmb();
3016 } else 3017 } else
3017 crq = NULL; 3018 crq = NULL;
3018 3019
@@ -3035,6 +3036,7 @@ static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost)
3035 if (crq->valid & 0x80) { 3036 if (crq->valid & 0x80) {
3036 if (++queue->cur == queue->size) 3037 if (++queue->cur == queue->size)
3037 queue->cur = 0; 3038 queue->cur = 0;
3039 rmb();
3038 } else 3040 } else
3039 crq = NULL; 3041 crq = NULL;
3040 3042
@@ -3083,12 +3085,14 @@ static void ibmvfc_tasklet(void *data)
3083 while ((async = ibmvfc_next_async_crq(vhost)) != NULL) { 3085 while ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
3084 ibmvfc_handle_async(async, vhost); 3086 ibmvfc_handle_async(async, vhost);
3085 async->valid = 0; 3087 async->valid = 0;
3088 wmb();
3086 } 3089 }
3087 3090
3088 /* Pull all the valid messages off the CRQ */ 3091 /* Pull all the valid messages off the CRQ */
3089 while ((crq = ibmvfc_next_crq(vhost)) != NULL) { 3092 while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
3090 ibmvfc_handle_crq(crq, vhost); 3093 ibmvfc_handle_crq(crq, vhost);
3091 crq->valid = 0; 3094 crq->valid = 0;
3095 wmb();
3092 } 3096 }
3093 3097
3094 vio_enable_interrupts(vdev); 3098 vio_enable_interrupts(vdev);
@@ -3096,10 +3100,12 @@ static void ibmvfc_tasklet(void *data)
3096 vio_disable_interrupts(vdev); 3100 vio_disable_interrupts(vdev);
3097 ibmvfc_handle_async(async, vhost); 3101 ibmvfc_handle_async(async, vhost);
3098 async->valid = 0; 3102 async->valid = 0;
3103 wmb();
3099 } else if ((crq = ibmvfc_next_crq(vhost)) != NULL) { 3104 } else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
3100 vio_disable_interrupts(vdev); 3105 vio_disable_interrupts(vdev);
3101 ibmvfc_handle_crq(crq, vhost); 3106 ibmvfc_handle_crq(crq, vhost);
3102 crq->valid = 0; 3107 crq->valid = 0;
3108 wmb();
3103 } else 3109 } else
3104 done = 1; 3110 done = 1;
3105 } 3111 }