diff options
author | Matt Gates <matthew.gates@hp.com> | 2012-05-01 12:43:06 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-05-10 04:16:25 -0400 |
commit | 254f796b9f22b1944c64caabc356a56caaa2facd (patch) | |
tree | 4c5ee6950b15456b0d11c3c36587fa659baf6632 /drivers/scsi/hpsa.h | |
parent | 1d94f94d89848762306b4a8bd5e658c11828ab12 (diff) |
[SCSI] hpsa: use multiple reply queues
Smart Arrays can support multiple reply queues onto which command
completions may be deposited. It can help performance quite a bit
to arrange for command completions to be processed on the same CPU
from which they were submitted to increase the likelihood of cache
hits.
Signed-off-by: Matt Gates <matthew.gates@hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/hpsa.h')
-rw-r--r-- | drivers/scsi/hpsa.h | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index d8aa95c43f4d..486a7c099246 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h | |||
@@ -34,7 +34,7 @@ struct access_method { | |||
34 | void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); | 34 | void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); |
35 | unsigned long (*fifo_full)(struct ctlr_info *h); | 35 | unsigned long (*fifo_full)(struct ctlr_info *h); |
36 | bool (*intr_pending)(struct ctlr_info *h); | 36 | bool (*intr_pending)(struct ctlr_info *h); |
37 | unsigned long (*command_completed)(struct ctlr_info *h); | 37 | unsigned long (*command_completed)(struct ctlr_info *h, u8 q); |
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct hpsa_scsi_dev_t { | 40 | struct hpsa_scsi_dev_t { |
@@ -48,6 +48,13 @@ struct hpsa_scsi_dev_t { | |||
48 | unsigned char raid_level; /* from inquiry page 0xC1 */ | 48 | unsigned char raid_level; /* from inquiry page 0xC1 */ |
49 | }; | 49 | }; |
50 | 50 | ||
51 | struct reply_pool { | ||
52 | u64 *head; | ||
53 | size_t size; | ||
54 | u8 wraparound; | ||
55 | u32 current_entry; | ||
56 | }; | ||
57 | |||
51 | struct ctlr_info { | 58 | struct ctlr_info { |
52 | int ctlr; | 59 | int ctlr; |
53 | char devname[8]; | 60 | char devname[8]; |
@@ -68,7 +75,7 @@ struct ctlr_info { | |||
68 | # define DOORBELL_INT 1 | 75 | # define DOORBELL_INT 1 |
69 | # define SIMPLE_MODE_INT 2 | 76 | # define SIMPLE_MODE_INT 2 |
70 | # define MEMQ_MODE_INT 3 | 77 | # define MEMQ_MODE_INT 3 |
71 | unsigned int intr[4]; | 78 | unsigned int intr[MAX_REPLY_QUEUES]; |
72 | unsigned int msix_vector; | 79 | unsigned int msix_vector; |
73 | unsigned int msi_vector; | 80 | unsigned int msi_vector; |
74 | int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */ | 81 | int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */ |
@@ -111,13 +118,13 @@ struct ctlr_info { | |||
111 | unsigned long transMethod; | 118 | unsigned long transMethod; |
112 | 119 | ||
113 | /* | 120 | /* |
114 | * Performant mode completion buffer | 121 | * Performant mode completion buffers |
115 | */ | 122 | */ |
116 | u64 *reply_pool; | 123 | u64 *reply_pool; |
117 | dma_addr_t reply_pool_dhandle; | ||
118 | u64 *reply_pool_head; | ||
119 | size_t reply_pool_size; | 124 | size_t reply_pool_size; |
120 | unsigned char reply_pool_wraparound; | 125 | struct reply_pool reply_queue[MAX_REPLY_QUEUES]; |
126 | u8 nreply_queues; | ||
127 | dma_addr_t reply_pool_dhandle; | ||
121 | u32 *blockFetchTable; | 128 | u32 *blockFetchTable; |
122 | unsigned char *hba_inquiry_data; | 129 | unsigned char *hba_inquiry_data; |
123 | u64 last_intr_timestamp; | 130 | u64 last_intr_timestamp; |
@@ -125,6 +132,8 @@ struct ctlr_info { | |||
125 | u64 last_heartbeat_timestamp; | 132 | u64 last_heartbeat_timestamp; |
126 | u32 lockup_detected; | 133 | u32 lockup_detected; |
127 | struct list_head lockup_list; | 134 | struct list_head lockup_list; |
135 | /* Address of h->q[x] is passed to intr handler to know which queue */ | ||
136 | u8 q[MAX_REPLY_QUEUES]; | ||
128 | u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ | 137 | u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ |
129 | #define HPSATMF_BITS_SUPPORTED (1 << 0) | 138 | #define HPSATMF_BITS_SUPPORTED (1 << 0) |
130 | #define HPSATMF_PHYS_LUN_RESET (1 << 1) | 139 | #define HPSATMF_PHYS_LUN_RESET (1 << 1) |
@@ -275,8 +284,9 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) | |||
275 | } | 284 | } |
276 | } | 285 | } |
277 | 286 | ||
278 | static unsigned long SA5_performant_completed(struct ctlr_info *h) | 287 | static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) |
279 | { | 288 | { |
289 | struct reply_pool *rq = &h->reply_queue[q]; | ||
280 | unsigned long register_value = FIFO_EMPTY; | 290 | unsigned long register_value = FIFO_EMPTY; |
281 | 291 | ||
282 | /* msi auto clears the interrupt pending bit. */ | 292 | /* msi auto clears the interrupt pending bit. */ |
@@ -292,19 +302,18 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h) | |||
292 | register_value = readl(h->vaddr + SA5_OUTDB_STATUS); | 302 | register_value = readl(h->vaddr + SA5_OUTDB_STATUS); |
293 | } | 303 | } |
294 | 304 | ||
295 | if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { | 305 | if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { |
296 | register_value = *(h->reply_pool_head); | 306 | register_value = rq->head[rq->current_entry]; |
297 | (h->reply_pool_head)++; | 307 | rq->current_entry++; |
298 | h->commands_outstanding--; | 308 | h->commands_outstanding--; |
299 | } else { | 309 | } else { |
300 | register_value = FIFO_EMPTY; | 310 | register_value = FIFO_EMPTY; |
301 | } | 311 | } |
302 | /* Check for wraparound */ | 312 | /* Check for wraparound */ |
303 | if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { | 313 | if (rq->current_entry == h->max_commands) { |
304 | h->reply_pool_head = h->reply_pool; | 314 | rq->current_entry = 0; |
305 | h->reply_pool_wraparound ^= 1; | 315 | rq->wraparound ^= 1; |
306 | } | 316 | } |
307 | |||
308 | return register_value; | 317 | return register_value; |
309 | } | 318 | } |
310 | 319 | ||
@@ -324,7 +333,8 @@ static unsigned long SA5_fifo_full(struct ctlr_info *h) | |||
324 | * returns value read from hardware. | 333 | * returns value read from hardware. |
325 | * returns FIFO_EMPTY if there is nothing to read | 334 | * returns FIFO_EMPTY if there is nothing to read |
326 | */ | 335 | */ |
327 | static unsigned long SA5_completed(struct ctlr_info *h) | 336 | static unsigned long SA5_completed(struct ctlr_info *h, |
337 | __attribute__((unused)) u8 q) | ||
328 | { | 338 | { |
329 | unsigned long register_value | 339 | unsigned long register_value |
330 | = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); | 340 | = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); |