aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hpsa.h
diff options
context:
space:
mode:
authorDon Brace <brace@beardog.cce.hp.com>2010-02-04 09:42:40 -0500
committerJames Bottomley <James.Bottomley@suse.de>2010-02-17 14:20:26 -0500
commit303932fd4ff63e8650d5d5da6cc286a8b5f8318d (patch)
treef48d9a236ffa5a43ed873d429243a12ceb19aa93 /drivers/scsi/hpsa.h
parent900c54404a9456b3ff10745e5e8f64b12c3a6ef7 (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.h106
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 {
173static void SA5_submit_command(struct ctlr_info *h, 201static 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
229static 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
241static 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
319static 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
245static struct access_method SA5_access = { 334static 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
342static 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
253struct board_type { 350struct 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