diff options
author | Don Brace <brace@beardog.cce.hp.com> | 2010-02-04 09:42:40 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-02-17 14:20:26 -0500 |
commit | 303932fd4ff63e8650d5d5da6cc286a8b5f8318d (patch) | |
tree | f48d9a236ffa5a43ed873d429243a12ceb19aa93 /drivers/scsi/hpsa.h | |
parent | 900c54404a9456b3ff10745e5e8f64b12c3a6ef7 (diff) |
[SCSI] hpsa: Allow multiple command completions per interrupt.
This is done by adding support for the so-called "performant mode"
(that's really what they called it). Smart Array controllers
have a mode which enables multiple command completions to be
delivered with a single interrupt, "performant" mode. We want to use
that mode, as some newer controllers will be requiring this mode.
Signed-off-by: Don Brace <brace@beardog.cce.hp.com>
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Mike Miller <mikem@beardog.cce.hp.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/hpsa.h')
-rw-r--r-- | drivers/scsi/hpsa.h | 106 |
1 files changed, 100 insertions, 6 deletions
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 0eab386a03be..0ba1aa3f4d4d 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h | |||
@@ -60,14 +60,15 @@ struct ctlr_info { | |||
60 | unsigned long paddr; | 60 | unsigned long paddr; |
61 | int nr_cmds; /* Number of commands allowed on this controller */ | 61 | int nr_cmds; /* Number of commands allowed on this controller */ |
62 | struct CfgTable __iomem *cfgtable; | 62 | struct CfgTable __iomem *cfgtable; |
63 | int max_sg_entries; | ||
63 | int interrupts_enabled; | 64 | int interrupts_enabled; |
64 | int major; | 65 | int major; |
65 | int max_commands; | 66 | int max_commands; |
66 | int commands_outstanding; | 67 | int commands_outstanding; |
67 | int max_outstanding; /* Debug */ | 68 | int max_outstanding; /* Debug */ |
68 | int usage_count; /* number of opens all all minor devices */ | 69 | int usage_count; /* number of opens all all minor devices */ |
69 | # define DOORBELL_INT 0 | 70 | # define PERF_MODE_INT 0 |
70 | # define PERF_MODE_INT 1 | 71 | # define DOORBELL_INT 1 |
71 | # define SIMPLE_MODE_INT 2 | 72 | # define SIMPLE_MODE_INT 2 |
72 | # define MEMQ_MODE_INT 3 | 73 | # define MEMQ_MODE_INT 3 |
73 | unsigned int intr[4]; | 74 | unsigned int intr[4]; |
@@ -102,6 +103,23 @@ struct ctlr_info { | |||
102 | int ndevices; /* number of used elements in .dev[] array. */ | 103 | int ndevices; /* number of used elements in .dev[] array. */ |
103 | #define HPSA_MAX_SCSI_DEVS_PER_HBA 256 | 104 | #define HPSA_MAX_SCSI_DEVS_PER_HBA 256 |
104 | struct hpsa_scsi_dev_t *dev[HPSA_MAX_SCSI_DEVS_PER_HBA]; | 105 | struct hpsa_scsi_dev_t *dev[HPSA_MAX_SCSI_DEVS_PER_HBA]; |
106 | /* | ||
107 | * Performant mode tables. | ||
108 | */ | ||
109 | u32 trans_support; | ||
110 | u32 trans_offset; | ||
111 | struct TransTable_struct *transtable; | ||
112 | unsigned long transMethod; | ||
113 | |||
114 | /* | ||
115 | * Performant mode completion buffer | ||
116 | */ | ||
117 | u64 *reply_pool; | ||
118 | dma_addr_t reply_pool_dhandle; | ||
119 | u64 *reply_pool_head; | ||
120 | size_t reply_pool_size; | ||
121 | unsigned char reply_pool_wraparound; | ||
122 | u32 *blockFetchTable; | ||
105 | }; | 123 | }; |
106 | #define HPSA_ABORT_MSG 0 | 124 | #define HPSA_ABORT_MSG 0 |
107 | #define HPSA_DEVICE_RESET_MSG 1 | 125 | #define HPSA_DEVICE_RESET_MSG 1 |
@@ -165,6 +183,16 @@ struct ctlr_info { | |||
165 | 183 | ||
166 | #define HPSA_ERROR_BIT 0x02 | 184 | #define HPSA_ERROR_BIT 0x02 |
167 | 185 | ||
186 | /* Performant mode flags */ | ||
187 | #define SA5_PERF_INTR_PENDING 0x04 | ||
188 | #define SA5_PERF_INTR_OFF 0x05 | ||
189 | #define SA5_OUTDB_STATUS_PERF_BIT 0x01 | ||
190 | #define SA5_OUTDB_CLEAR_PERF_BIT 0x01 | ||
191 | #define SA5_OUTDB_CLEAR 0xA0 | ||
192 | #define SA5_OUTDB_CLEAR_PERF_BIT 0x01 | ||
193 | #define SA5_OUTDB_STATUS 0x9C | ||
194 | |||
195 | |||
168 | #define HPSA_INTR_ON 1 | 196 | #define HPSA_INTR_ON 1 |
169 | #define HPSA_INTR_OFF 0 | 197 | #define HPSA_INTR_OFF 0 |
170 | /* | 198 | /* |
@@ -173,7 +201,8 @@ struct ctlr_info { | |||
173 | static void SA5_submit_command(struct ctlr_info *h, | 201 | static void SA5_submit_command(struct ctlr_info *h, |
174 | struct CommandList *c) | 202 | struct CommandList *c) |
175 | { | 203 | { |
176 | dev_dbg(&h->pdev->dev, "Sending %x\n", c->busaddr); | 204 | dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, |
205 | c->Header.Tag.lower); | ||
177 | writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); | 206 | writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); |
178 | h->commands_outstanding++; | 207 | h->commands_outstanding++; |
179 | if (h->commands_outstanding > h->max_outstanding) | 208 | if (h->commands_outstanding > h->max_outstanding) |
@@ -196,6 +225,52 @@ static void SA5_intr_mask(struct ctlr_info *h, unsigned long val) | |||
196 | h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); | 225 | h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); |
197 | } | 226 | } |
198 | } | 227 | } |
228 | |||
229 | static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) | ||
230 | { | ||
231 | if (val) { /* turn on interrupts */ | ||
232 | h->interrupts_enabled = 1; | ||
233 | writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); | ||
234 | } else { | ||
235 | h->interrupts_enabled = 0; | ||
236 | writel(SA5_PERF_INTR_OFF, | ||
237 | h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | static unsigned long SA5_performant_completed(struct ctlr_info *h) | ||
242 | { | ||
243 | unsigned long register_value = FIFO_EMPTY; | ||
244 | |||
245 | /* flush the controller write of the reply queue by reading | ||
246 | * outbound doorbell status register. | ||
247 | */ | ||
248 | register_value = readl(h->vaddr + SA5_OUTDB_STATUS); | ||
249 | /* msi auto clears the interrupt pending bit. */ | ||
250 | if (!(h->msi_vector || h->msix_vector)) { | ||
251 | writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); | ||
252 | /* Do a read in order to flush the write to the controller | ||
253 | * (as per spec.) | ||
254 | */ | ||
255 | register_value = readl(h->vaddr + SA5_OUTDB_STATUS); | ||
256 | } | ||
257 | |||
258 | if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { | ||
259 | register_value = *(h->reply_pool_head); | ||
260 | (h->reply_pool_head)++; | ||
261 | h->commands_outstanding--; | ||
262 | } else { | ||
263 | register_value = FIFO_EMPTY; | ||
264 | } | ||
265 | /* Check for wraparound */ | ||
266 | if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { | ||
267 | h->reply_pool_head = h->reply_pool; | ||
268 | h->reply_pool_wraparound ^= 1; | ||
269 | } | ||
270 | |||
271 | return register_value; | ||
272 | } | ||
273 | |||
199 | /* | 274 | /* |
200 | * Returns true if fifo is full. | 275 | * Returns true if fifo is full. |
201 | * | 276 | * |
@@ -241,6 +316,20 @@ static bool SA5_intr_pending(struct ctlr_info *h) | |||
241 | return register_value & SA5_INTR_PENDING; | 316 | return register_value & SA5_INTR_PENDING; |
242 | } | 317 | } |
243 | 318 | ||
319 | static bool SA5_performant_intr_pending(struct ctlr_info *h) | ||
320 | { | ||
321 | unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS); | ||
322 | |||
323 | if (!register_value) | ||
324 | return false; | ||
325 | |||
326 | if (h->msi_vector || h->msix_vector) | ||
327 | return true; | ||
328 | |||
329 | /* Read outbound doorbell to flush */ | ||
330 | register_value = readl(h->vaddr + SA5_OUTDB_STATUS); | ||
331 | return register_value & SA5_OUTDB_STATUS_PERF_BIT; | ||
332 | } | ||
244 | 333 | ||
245 | static struct access_method SA5_access = { | 334 | static struct access_method SA5_access = { |
246 | SA5_submit_command, | 335 | SA5_submit_command, |
@@ -250,14 +339,19 @@ static struct access_method SA5_access = { | |||
250 | SA5_completed, | 339 | SA5_completed, |
251 | }; | 340 | }; |
252 | 341 | ||
342 | static struct access_method SA5_performant_access = { | ||
343 | SA5_submit_command, | ||
344 | SA5_performant_intr_mask, | ||
345 | SA5_fifo_full, | ||
346 | SA5_performant_intr_pending, | ||
347 | SA5_performant_completed, | ||
348 | }; | ||
349 | |||
253 | struct board_type { | 350 | struct board_type { |
254 | u32 board_id; | 351 | u32 board_id; |
255 | char *product_name; | 352 | char *product_name; |
256 | struct access_method *access; | 353 | struct access_method *access; |
257 | }; | 354 | }; |
258 | 355 | ||
259 | |||
260 | /* end of old hpsa_scsi.h file */ | ||
261 | |||
262 | #endif /* HPSA_H */ | 356 | #endif /* HPSA_H */ |
263 | 357 | ||