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 | |
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')
-rw-r--r-- | drivers/scsi/hpsa.c | 286 | ||||
-rw-r--r-- | drivers/scsi/hpsa.h | 106 | ||||
-rw-r--r-- | drivers/scsi/hpsa_cmd.h | 78 |
3 files changed, 404 insertions, 66 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 314854b455d2..e518766f9fe0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c | |||
@@ -150,6 +150,11 @@ static int check_for_unit_attention(struct ctlr_info *h, | |||
150 | struct CommandList *c); | 150 | struct CommandList *c); |
151 | static void check_ioctl_unit_attention(struct ctlr_info *h, | 151 | static void check_ioctl_unit_attention(struct ctlr_info *h, |
152 | struct CommandList *c); | 152 | struct CommandList *c); |
153 | /* performant mode helper functions */ | ||
154 | static void calc_bucket_map(int *bucket, int num_buckets, | ||
155 | int nsgs, int *bucket_map); | ||
156 | static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); | ||
157 | static inline u32 next_command(struct ctlr_info *h); | ||
153 | 158 | ||
154 | static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); | 159 | static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); |
155 | static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); | 160 | static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); |
@@ -173,10 +178,8 @@ static struct scsi_host_template hpsa_driver_template = { | |||
173 | .name = "hpsa", | 178 | .name = "hpsa", |
174 | .proc_name = "hpsa", | 179 | .proc_name = "hpsa", |
175 | .queuecommand = hpsa_scsi_queue_command, | 180 | .queuecommand = hpsa_scsi_queue_command, |
176 | .can_queue = 512, | ||
177 | .this_id = -1, | 181 | .this_id = -1, |
178 | .sg_tablesize = MAXSGENTRIES, | 182 | .sg_tablesize = MAXSGENTRIES, |
179 | .cmd_per_lun = 512, | ||
180 | .use_clustering = ENABLE_CLUSTERING, | 183 | .use_clustering = ENABLE_CLUSTERING, |
181 | .eh_device_reset_handler = hpsa_eh_device_reset_handler, | 184 | .eh_device_reset_handler = hpsa_eh_device_reset_handler, |
182 | .ioctl = hpsa_ioctl, | 185 | .ioctl = hpsa_ioctl, |
@@ -394,10 +397,44 @@ static inline void addQ(struct hlist_head *list, struct CommandList *c) | |||
394 | hlist_add_head(&c->list, list); | 397 | hlist_add_head(&c->list, list); |
395 | } | 398 | } |
396 | 399 | ||
400 | static inline u32 next_command(struct ctlr_info *h) | ||
401 | { | ||
402 | u32 a; | ||
403 | |||
404 | if (unlikely(h->transMethod != CFGTBL_Trans_Performant)) | ||
405 | return h->access.command_completed(h); | ||
406 | |||
407 | if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { | ||
408 | a = *(h->reply_pool_head); /* Next cmd in ring buffer */ | ||
409 | (h->reply_pool_head)++; | ||
410 | h->commands_outstanding--; | ||
411 | } else { | ||
412 | a = FIFO_EMPTY; | ||
413 | } | ||
414 | /* Check for wraparound */ | ||
415 | if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { | ||
416 | h->reply_pool_head = h->reply_pool; | ||
417 | h->reply_pool_wraparound ^= 1; | ||
418 | } | ||
419 | return a; | ||
420 | } | ||
421 | |||
422 | /* set_performant_mode: Modify the tag for cciss performant | ||
423 | * set bit 0 for pull model, bits 3-1 for block fetch | ||
424 | * register number | ||
425 | */ | ||
426 | static void set_performant_mode(struct ctlr_info *h, struct CommandList *c) | ||
427 | { | ||
428 | if (likely(h->transMethod == CFGTBL_Trans_Performant)) | ||
429 | c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); | ||
430 | } | ||
431 | |||
397 | static void enqueue_cmd_and_start_io(struct ctlr_info *h, | 432 | static void enqueue_cmd_and_start_io(struct ctlr_info *h, |
398 | struct CommandList *c) | 433 | struct CommandList *c) |
399 | { | 434 | { |
400 | unsigned long flags; | 435 | unsigned long flags; |
436 | |||
437 | set_performant_mode(h, c); | ||
401 | spin_lock_irqsave(&h->lock, flags); | 438 | spin_lock_irqsave(&h->lock, flags); |
402 | addQ(&h->reqQ, c); | 439 | addQ(&h->reqQ, c); |
403 | h->Qdepth++; | 440 | h->Qdepth++; |
@@ -1116,9 +1153,11 @@ static int hpsa_scsi_detect(struct ctlr_info *h) | |||
1116 | sh->max_cmd_len = MAX_COMMAND_SIZE; | 1153 | sh->max_cmd_len = MAX_COMMAND_SIZE; |
1117 | sh->max_lun = HPSA_MAX_LUN; | 1154 | sh->max_lun = HPSA_MAX_LUN; |
1118 | sh->max_id = HPSA_MAX_LUN; | 1155 | sh->max_id = HPSA_MAX_LUN; |
1156 | sh->can_queue = h->nr_cmds; | ||
1157 | sh->cmd_per_lun = h->nr_cmds; | ||
1119 | h->scsi_host = sh; | 1158 | h->scsi_host = sh; |
1120 | sh->hostdata[0] = (unsigned long) h; | 1159 | sh->hostdata[0] = (unsigned long) h; |
1121 | sh->irq = h->intr[SIMPLE_MODE_INT]; | 1160 | sh->irq = h->intr[PERF_MODE_INT]; |
1122 | sh->unique_id = sh->irq; | 1161 | sh->unique_id = sh->irq; |
1123 | error = scsi_add_host(sh, &h->pdev->dev); | 1162 | error = scsi_add_host(sh, &h->pdev->dev); |
1124 | if (error) | 1163 | if (error) |
@@ -1843,7 +1882,8 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd, | |||
1843 | c->scsi_cmd = cmd; | 1882 | c->scsi_cmd = cmd; |
1844 | c->Header.ReplyQueue = 0; /* unused in simple mode */ | 1883 | c->Header.ReplyQueue = 0; /* unused in simple mode */ |
1845 | memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); | 1884 | memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); |
1846 | c->Header.Tag.lower = c->busaddr; /* Use k. address of cmd as tag */ | 1885 | c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT); |
1886 | c->Header.Tag.lower |= DIRECT_LOOKUP_BIT; | ||
1847 | 1887 | ||
1848 | /* Fill in the request block... */ | 1888 | /* Fill in the request block... */ |
1849 | 1889 | ||
@@ -2700,8 +2740,9 @@ static inline bool interrupt_pending(struct ctlr_info *h) | |||
2700 | 2740 | ||
2701 | static inline long interrupt_not_for_us(struct ctlr_info *h) | 2741 | static inline long interrupt_not_for_us(struct ctlr_info *h) |
2702 | { | 2742 | { |
2703 | return ((h->access.intr_pending(h) == 0) || | 2743 | return !(h->msi_vector || h->msix_vector) && |
2704 | (h->interrupts_enabled == 0)); | 2744 | ((h->access.intr_pending(h) == 0) || |
2745 | (h->interrupts_enabled == 0)); | ||
2705 | } | 2746 | } |
2706 | 2747 | ||
2707 | static inline int bad_tag(struct ctlr_info *h, u32 tag_index, | 2748 | static inline int bad_tag(struct ctlr_info *h, u32 tag_index, |
@@ -2725,13 +2766,13 @@ static inline void finish_cmd(struct CommandList *c, u32 raw_tag) | |||
2725 | 2766 | ||
2726 | static inline u32 hpsa_tag_contains_index(u32 tag) | 2767 | static inline u32 hpsa_tag_contains_index(u32 tag) |
2727 | { | 2768 | { |
2728 | #define DIRECT_LOOKUP_BIT 0x04 | 2769 | #define DIRECT_LOOKUP_BIT 0x10 |
2729 | return tag & DIRECT_LOOKUP_BIT; | 2770 | return tag & DIRECT_LOOKUP_BIT; |
2730 | } | 2771 | } |
2731 | 2772 | ||
2732 | static inline u32 hpsa_tag_to_index(u32 tag) | 2773 | static inline u32 hpsa_tag_to_index(u32 tag) |
2733 | { | 2774 | { |
2734 | #define DIRECT_LOOKUP_SHIFT 3 | 2775 | #define DIRECT_LOOKUP_SHIFT 5 |
2735 | return tag >> DIRECT_LOOKUP_SHIFT; | 2776 | return tag >> DIRECT_LOOKUP_SHIFT; |
2736 | } | 2777 | } |
2737 | 2778 | ||
@@ -2741,42 +2782,61 @@ static inline u32 hpsa_tag_discard_error_bits(u32 tag) | |||
2741 | return tag & ~HPSA_ERROR_BITS; | 2782 | return tag & ~HPSA_ERROR_BITS; |
2742 | } | 2783 | } |
2743 | 2784 | ||
2785 | /* process completion of an indexed ("direct lookup") command */ | ||
2786 | static inline u32 process_indexed_cmd(struct ctlr_info *h, | ||
2787 | u32 raw_tag) | ||
2788 | { | ||
2789 | u32 tag_index; | ||
2790 | struct CommandList *c; | ||
2791 | |||
2792 | tag_index = hpsa_tag_to_index(raw_tag); | ||
2793 | if (bad_tag(h, tag_index, raw_tag)) | ||
2794 | return next_command(h); | ||
2795 | c = h->cmd_pool + tag_index; | ||
2796 | finish_cmd(c, raw_tag); | ||
2797 | return next_command(h); | ||
2798 | } | ||
2799 | |||
2800 | /* process completion of a non-indexed command */ | ||
2801 | static inline u32 process_nonindexed_cmd(struct ctlr_info *h, | ||
2802 | u32 raw_tag) | ||
2803 | { | ||
2804 | u32 tag; | ||
2805 | struct CommandList *c = NULL; | ||
2806 | struct hlist_node *tmp; | ||
2807 | |||
2808 | tag = hpsa_tag_discard_error_bits(raw_tag); | ||
2809 | hlist_for_each_entry(c, tmp, &h->cmpQ, list) { | ||
2810 | if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) { | ||
2811 | finish_cmd(c, raw_tag); | ||
2812 | return next_command(h); | ||
2813 | } | ||
2814 | } | ||
2815 | bad_tag(h, h->nr_cmds + 1, raw_tag); | ||
2816 | return next_command(h); | ||
2817 | } | ||
2818 | |||
2744 | static irqreturn_t do_hpsa_intr(int irq, void *dev_id) | 2819 | static irqreturn_t do_hpsa_intr(int irq, void *dev_id) |
2745 | { | 2820 | { |
2746 | struct ctlr_info *h = dev_id; | 2821 | struct ctlr_info *h = dev_id; |
2747 | struct CommandList *c; | ||
2748 | unsigned long flags; | 2822 | unsigned long flags; |
2749 | u32 raw_tag, tag, tag_index; | 2823 | u32 raw_tag; |
2750 | struct hlist_node *tmp; | ||
2751 | 2824 | ||
2752 | if (interrupt_not_for_us(h)) | 2825 | if (interrupt_not_for_us(h)) |
2753 | return IRQ_NONE; | 2826 | return IRQ_NONE; |
2754 | spin_lock_irqsave(&h->lock, flags); | 2827 | spin_lock_irqsave(&h->lock, flags); |
2755 | while (interrupt_pending(h)) { | 2828 | raw_tag = get_next_completion(h); |
2756 | while ((raw_tag = get_next_completion(h)) != FIFO_EMPTY) { | 2829 | while (raw_tag != FIFO_EMPTY) { |
2757 | if (likely(hpsa_tag_contains_index(raw_tag))) { | 2830 | if (hpsa_tag_contains_index(raw_tag)) |
2758 | tag_index = hpsa_tag_to_index(raw_tag); | 2831 | raw_tag = process_indexed_cmd(h, raw_tag); |
2759 | if (bad_tag(h, tag_index, raw_tag)) | 2832 | else |
2760 | return IRQ_HANDLED; | 2833 | raw_tag = process_nonindexed_cmd(h, raw_tag); |
2761 | c = h->cmd_pool + tag_index; | ||
2762 | finish_cmd(c, raw_tag); | ||
2763 | continue; | ||
2764 | } | ||
2765 | tag = hpsa_tag_discard_error_bits(raw_tag); | ||
2766 | c = NULL; | ||
2767 | hlist_for_each_entry(c, tmp, &h->cmpQ, list) { | ||
2768 | if (c->busaddr == tag) { | ||
2769 | finish_cmd(c, raw_tag); | ||
2770 | break; | ||
2771 | } | ||
2772 | } | ||
2773 | } | ||
2774 | } | 2834 | } |
2775 | spin_unlock_irqrestore(&h->lock, flags); | 2835 | spin_unlock_irqrestore(&h->lock, flags); |
2776 | return IRQ_HANDLED; | 2836 | return IRQ_HANDLED; |
2777 | } | 2837 | } |
2778 | 2838 | ||
2779 | /* Send a message CDB to the firmware. */ | 2839 | /* Send a message CDB to the firmwart. */ |
2780 | static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode, | 2840 | static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode, |
2781 | unsigned char type) | 2841 | unsigned char type) |
2782 | { | 2842 | { |
@@ -3108,7 +3168,7 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h, | |||
3108 | default_int_mode: | 3168 | default_int_mode: |
3109 | #endif /* CONFIG_PCI_MSI */ | 3169 | #endif /* CONFIG_PCI_MSI */ |
3110 | /* if we get here we're going to use the default interrupt mode */ | 3170 | /* if we get here we're going to use the default interrupt mode */ |
3111 | h->intr[SIMPLE_MODE_INT] = pdev->irq; | 3171 | h->intr[PERF_MODE_INT] = pdev->irq; |
3112 | } | 3172 | } |
3113 | 3173 | ||
3114 | static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) | 3174 | static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) |
@@ -3118,6 +3178,7 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) | |||
3118 | u64 cfg_offset; | 3178 | u64 cfg_offset; |
3119 | u32 cfg_base_addr; | 3179 | u32 cfg_base_addr; |
3120 | u64 cfg_base_addr_index; | 3180 | u64 cfg_base_addr_index; |
3181 | u32 trans_offset; | ||
3121 | int i, prod_index, err; | 3182 | int i, prod_index, err; |
3122 | 3183 | ||
3123 | subsystem_vendor_id = pdev->subsystem_vendor; | 3184 | subsystem_vendor_id = pdev->subsystem_vendor; |
@@ -3211,11 +3272,14 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) | |||
3211 | h->cfgtable = remap_pci_mem(pci_resource_start(pdev, | 3272 | h->cfgtable = remap_pci_mem(pci_resource_start(pdev, |
3212 | cfg_base_addr_index) + cfg_offset, | 3273 | cfg_base_addr_index) + cfg_offset, |
3213 | sizeof(h->cfgtable)); | 3274 | sizeof(h->cfgtable)); |
3214 | h->board_id = board_id; | 3275 | /* Find performant mode table. */ |
3215 | 3276 | trans_offset = readl(&(h->cfgtable->TransMethodOffset)); | |
3216 | /* Query controller for max supported commands: */ | 3277 | h->transtable = remap_pci_mem(pci_resource_start(pdev, |
3217 | h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); | 3278 | cfg_base_addr_index)+cfg_offset+trans_offset, |
3279 | sizeof(*h->transtable)); | ||
3218 | 3280 | ||
3281 | h->board_id = board_id; | ||
3282 | h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); | ||
3219 | h->product_name = products[prod_index].product_name; | 3283 | h->product_name = products[prod_index].product_name; |
3220 | h->access = *(products[prod_index].access); | 3284 | h->access = *(products[prod_index].access); |
3221 | /* Allow room for some ioctls */ | 3285 | /* Allow room for some ioctls */ |
@@ -3314,7 +3378,12 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, | |||
3314 | } | 3378 | } |
3315 | } | 3379 | } |
3316 | 3380 | ||
3317 | BUILD_BUG_ON(sizeof(struct CommandList) % 8); | 3381 | /* Command structures must be aligned on a 32-byte boundary because |
3382 | * the 5 lower bits of the address are used by the hardware. and by | ||
3383 | * the driver. See comments in hpsa.h for more info. | ||
3384 | */ | ||
3385 | #define COMMANDLIST_ALIGNMENT 32 | ||
3386 | BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT); | ||
3318 | h = kzalloc(sizeof(*h), GFP_KERNEL); | 3387 | h = kzalloc(sizeof(*h), GFP_KERNEL); |
3319 | if (!h) | 3388 | if (!h) |
3320 | return -ENOMEM; | 3389 | return -ENOMEM; |
@@ -3349,17 +3418,17 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, | |||
3349 | 3418 | ||
3350 | /* make sure the board interrupts are off */ | 3419 | /* make sure the board interrupts are off */ |
3351 | h->access.set_intr_mask(h, HPSA_INTR_OFF); | 3420 | h->access.set_intr_mask(h, HPSA_INTR_OFF); |
3352 | rc = request_irq(h->intr[SIMPLE_MODE_INT], do_hpsa_intr, | 3421 | rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr, |
3353 | IRQF_DISABLED | IRQF_SHARED, h->devname, h); | 3422 | IRQF_DISABLED, h->devname, h); |
3354 | if (rc) { | 3423 | if (rc) { |
3355 | dev_err(&pdev->dev, "unable to get irq %d for %s\n", | 3424 | dev_err(&pdev->dev, "unable to get irq %d for %s\n", |
3356 | h->intr[SIMPLE_MODE_INT], h->devname); | 3425 | h->intr[PERF_MODE_INT], h->devname); |
3357 | goto clean2; | 3426 | goto clean2; |
3358 | } | 3427 | } |
3359 | 3428 | ||
3360 | dev_info(&pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", | 3429 | dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", |
3361 | h->devname, pdev->device, pci_name(pdev), | 3430 | h->devname, pdev->device, |
3362 | h->intr[SIMPLE_MODE_INT], dac ? "" : " not"); | 3431 | h->intr[PERF_MODE_INT], dac ? "" : " not"); |
3363 | 3432 | ||
3364 | h->cmd_pool_bits = | 3433 | h->cmd_pool_bits = |
3365 | kmalloc(((h->nr_cmds + BITS_PER_LONG - | 3434 | kmalloc(((h->nr_cmds + BITS_PER_LONG - |
@@ -3389,6 +3458,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, | |||
3389 | /* Turn the interrupts on so we can service requests */ | 3458 | /* Turn the interrupts on so we can service requests */ |
3390 | h->access.set_intr_mask(h, HPSA_INTR_ON); | 3459 | h->access.set_intr_mask(h, HPSA_INTR_ON); |
3391 | 3460 | ||
3461 | hpsa_put_ctlr_into_performant_mode(h); | ||
3392 | hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ | 3462 | hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ |
3393 | h->busy_initializing = 0; | 3463 | h->busy_initializing = 0; |
3394 | return 1; | 3464 | return 1; |
@@ -3404,7 +3474,7 @@ clean4: | |||
3404 | h->nr_cmds * sizeof(struct ErrorInfo), | 3474 | h->nr_cmds * sizeof(struct ErrorInfo), |
3405 | h->errinfo_pool, | 3475 | h->errinfo_pool, |
3406 | h->errinfo_pool_dhandle); | 3476 | h->errinfo_pool_dhandle); |
3407 | free_irq(h->intr[SIMPLE_MODE_INT], h); | 3477 | free_irq(h->intr[PERF_MODE_INT], h); |
3408 | clean2: | 3478 | clean2: |
3409 | clean1: | 3479 | clean1: |
3410 | h->busy_initializing = 0; | 3480 | h->busy_initializing = 0; |
@@ -3448,7 +3518,7 @@ static void hpsa_shutdown(struct pci_dev *pdev) | |||
3448 | */ | 3518 | */ |
3449 | hpsa_flush_cache(h); | 3519 | hpsa_flush_cache(h); |
3450 | h->access.set_intr_mask(h, HPSA_INTR_OFF); | 3520 | h->access.set_intr_mask(h, HPSA_INTR_OFF); |
3451 | free_irq(h->intr[2], h); | 3521 | free_irq(h->intr[PERF_MODE_INT], h); |
3452 | #ifdef CONFIG_PCI_MSI | 3522 | #ifdef CONFIG_PCI_MSI |
3453 | if (h->msix_vector) | 3523 | if (h->msix_vector) |
3454 | pci_disable_msix(h->pdev); | 3524 | pci_disable_msix(h->pdev); |
@@ -3477,7 +3547,10 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev) | |||
3477 | pci_free_consistent(h->pdev, | 3547 | pci_free_consistent(h->pdev, |
3478 | h->nr_cmds * sizeof(struct ErrorInfo), | 3548 | h->nr_cmds * sizeof(struct ErrorInfo), |
3479 | h->errinfo_pool, h->errinfo_pool_dhandle); | 3549 | h->errinfo_pool, h->errinfo_pool_dhandle); |
3550 | pci_free_consistent(h->pdev, h->reply_pool_size, | ||
3551 | h->reply_pool, h->reply_pool_dhandle); | ||
3480 | kfree(h->cmd_pool_bits); | 3552 | kfree(h->cmd_pool_bits); |
3553 | kfree(h->blockFetchTable); | ||
3481 | /* | 3554 | /* |
3482 | * Deliberately omit pci_disable_device(): it does something nasty to | 3555 | * Deliberately omit pci_disable_device(): it does something nasty to |
3483 | * Smart Array controllers that pci_enable_device does not undo | 3556 | * Smart Array controllers that pci_enable_device does not undo |
@@ -3509,6 +3582,129 @@ static struct pci_driver hpsa_pci_driver = { | |||
3509 | .resume = hpsa_resume, | 3582 | .resume = hpsa_resume, |
3510 | }; | 3583 | }; |
3511 | 3584 | ||
3585 | /* Fill in bucket_map[], given nsgs (the max number of | ||
3586 | * scatter gather elements supported) and bucket[], | ||
3587 | * which is an array of 8 integers. The bucket[] array | ||
3588 | * contains 8 different DMA transfer sizes (in 16 | ||
3589 | * byte increments) which the controller uses to fetch | ||
3590 | * commands. This function fills in bucket_map[], which | ||
3591 | * maps a given number of scatter gather elements to one of | ||
3592 | * the 8 DMA transfer sizes. The point of it is to allow the | ||
3593 | * controller to only do as much DMA as needed to fetch the | ||
3594 | * command, with the DMA transfer size encoded in the lower | ||
3595 | * bits of the command address. | ||
3596 | */ | ||
3597 | static void calc_bucket_map(int bucket[], int num_buckets, | ||
3598 | int nsgs, int *bucket_map) | ||
3599 | { | ||
3600 | int i, j, b, size; | ||
3601 | |||
3602 | /* even a command with 0 SGs requires 4 blocks */ | ||
3603 | #define MINIMUM_TRANSFER_BLOCKS 4 | ||
3604 | #define NUM_BUCKETS 8 | ||
3605 | /* Note, bucket_map must have nsgs+1 entries. */ | ||
3606 | for (i = 0; i <= nsgs; i++) { | ||
3607 | /* Compute size of a command with i SG entries */ | ||
3608 | size = i + MINIMUM_TRANSFER_BLOCKS; | ||
3609 | b = num_buckets; /* Assume the biggest bucket */ | ||
3610 | /* Find the bucket that is just big enough */ | ||
3611 | for (j = 0; j < 8; j++) { | ||
3612 | if (bucket[j] >= size) { | ||
3613 | b = j; | ||
3614 | break; | ||
3615 | } | ||
3616 | } | ||
3617 | /* for a command with i SG entries, use bucket b. */ | ||
3618 | bucket_map[i] = b; | ||
3619 | } | ||
3620 | } | ||
3621 | |||
3622 | static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) | ||
3623 | { | ||
3624 | u32 trans_support; | ||
3625 | u64 trans_offset; | ||
3626 | /* 5 = 1 s/g entry or 4k | ||
3627 | * 6 = 2 s/g entry or 8k | ||
3628 | * 8 = 4 s/g entry or 16k | ||
3629 | * 10 = 6 s/g entry or 24k | ||
3630 | */ | ||
3631 | int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */ | ||
3632 | int i = 0; | ||
3633 | int l = 0; | ||
3634 | unsigned long register_value; | ||
3635 | |||
3636 | trans_support = readl(&(h->cfgtable->TransportSupport)); | ||
3637 | if (!(trans_support & PERFORMANT_MODE)) | ||
3638 | return; | ||
3639 | |||
3640 | h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); | ||
3641 | h->max_sg_entries = 32; | ||
3642 | /* Performant mode ring buffer and supporting data structures */ | ||
3643 | h->reply_pool_size = h->max_commands * sizeof(u64); | ||
3644 | h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size, | ||
3645 | &(h->reply_pool_dhandle)); | ||
3646 | |||
3647 | /* Need a block fetch table for performant mode */ | ||
3648 | h->blockFetchTable = kmalloc(((h->max_sg_entries+1) * | ||
3649 | sizeof(u32)), GFP_KERNEL); | ||
3650 | |||
3651 | if ((h->reply_pool == NULL) | ||
3652 | || (h->blockFetchTable == NULL)) | ||
3653 | goto clean_up; | ||
3654 | |||
3655 | h->reply_pool_wraparound = 1; /* spec: init to 1 */ | ||
3656 | |||
3657 | /* Controller spec: zero out this buffer. */ | ||
3658 | memset(h->reply_pool, 0, h->reply_pool_size); | ||
3659 | h->reply_pool_head = h->reply_pool; | ||
3660 | |||
3661 | trans_offset = readl(&(h->cfgtable->TransMethodOffset)); | ||
3662 | bft[7] = h->max_sg_entries + 4; | ||
3663 | calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable); | ||
3664 | for (i = 0; i < 8; i++) | ||
3665 | writel(bft[i], &h->transtable->BlockFetch[i]); | ||
3666 | |||
3667 | /* size of controller ring buffer */ | ||
3668 | writel(h->max_commands, &h->transtable->RepQSize); | ||
3669 | writel(1, &h->transtable->RepQCount); | ||
3670 | writel(0, &h->transtable->RepQCtrAddrLow32); | ||
3671 | writel(0, &h->transtable->RepQCtrAddrHigh32); | ||
3672 | writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32); | ||
3673 | writel(0, &h->transtable->RepQAddr0High32); | ||
3674 | writel(CFGTBL_Trans_Performant, | ||
3675 | &(h->cfgtable->HostWrite.TransportRequest)); | ||
3676 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | ||
3677 | /* under certain very rare conditions, this can take awhile. | ||
3678 | * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right | ||
3679 | * as we enter this code.) */ | ||
3680 | for (l = 0; l < MAX_CONFIG_WAIT; l++) { | ||
3681 | register_value = readl(h->vaddr + SA5_DOORBELL); | ||
3682 | if (!(register_value & CFGTBL_ChangeReq)) | ||
3683 | break; | ||
3684 | /* delay and try again */ | ||
3685 | set_current_state(TASK_INTERRUPTIBLE); | ||
3686 | schedule_timeout(10); | ||
3687 | } | ||
3688 | register_value = readl(&(h->cfgtable->TransportActive)); | ||
3689 | if (!(register_value & CFGTBL_Trans_Performant)) { | ||
3690 | dev_warn(&h->pdev->dev, "unable to get board into" | ||
3691 | " performant mode\n"); | ||
3692 | return; | ||
3693 | } | ||
3694 | |||
3695 | /* Change the access methods to the performant access methods */ | ||
3696 | h->access = SA5_performant_access; | ||
3697 | h->transMethod = CFGTBL_Trans_Performant; | ||
3698 | |||
3699 | return; | ||
3700 | |||
3701 | clean_up: | ||
3702 | if (h->reply_pool) | ||
3703 | pci_free_consistent(h->pdev, h->reply_pool_size, | ||
3704 | h->reply_pool, h->reply_pool_dhandle); | ||
3705 | kfree(h->blockFetchTable); | ||
3706 | } | ||
3707 | |||
3512 | /* | 3708 | /* |
3513 | * This is it. Register the PCI driver information for the cards we control | 3709 | * This is it. Register the PCI driver information for the cards we control |
3514 | * the OS will call our registered routines when it finds one of our cards. | 3710 | * the OS will call our registered routines when it finds one of our cards. |
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 | ||
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 88bb3b0a21d3..3e0abdf76689 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h | |||
@@ -101,6 +101,7 @@ | |||
101 | #define CFGTBL_AccCmds 0x00000001l | 101 | #define CFGTBL_AccCmds 0x00000001l |
102 | 102 | ||
103 | #define CFGTBL_Trans_Simple 0x00000002l | 103 | #define CFGTBL_Trans_Simple 0x00000002l |
104 | #define CFGTBL_Trans_Performant 0x00000004l | ||
104 | 105 | ||
105 | #define CFGTBL_BusType_Ultra2 0x00000001l | 106 | #define CFGTBL_BusType_Ultra2 0x00000001l |
106 | #define CFGTBL_BusType_Ultra3 0x00000002l | 107 | #define CFGTBL_BusType_Ultra3 0x00000002l |
@@ -267,12 +268,31 @@ struct ErrorInfo { | |||
267 | #define CMD_IOCTL_PEND 0x01 | 268 | #define CMD_IOCTL_PEND 0x01 |
268 | #define CMD_SCSI 0x03 | 269 | #define CMD_SCSI 0x03 |
269 | 270 | ||
271 | /* This structure needs to be divisible by 32 for new | ||
272 | * indexing method and performant mode. | ||
273 | */ | ||
274 | #define PAD32 32 | ||
275 | #define PAD64DIFF 0 | ||
276 | #define USEEXTRA ((sizeof(void *) - 4)/4) | ||
277 | #define PADSIZE (PAD32 + PAD64DIFF * USEEXTRA) | ||
278 | |||
279 | #define DIRECT_LOOKUP_SHIFT 5 | ||
280 | #define DIRECT_LOOKUP_BIT 0x10 | ||
281 | |||
282 | #define HPSA_ERROR_BIT 0x02 | ||
270 | struct ctlr_info; /* defined in hpsa.h */ | 283 | struct ctlr_info; /* defined in hpsa.h */ |
271 | /* The size of this structure needs to be divisible by 8 | 284 | /* The size of this structure needs to be divisible by 32 |
272 | * on all architectures, because the controller uses 2 | 285 | * on all architectures because low 5 bits of the addresses |
273 | * lower bits of the address, and the driver uses 1 lower | 286 | * are used as follows: |
274 | * bit (3 bits total.) | 287 | * |
288 | * bit 0: to device, used to indicate "performant mode" command | ||
289 | * from device, indidcates error status. | ||
290 | * bit 1-3: to device, indicates block fetch table entry for | ||
291 | * reducing DMA in fetching commands from host memory. | ||
292 | * bit 4: used to indicate whether tag is "direct lookup" (index), | ||
293 | * or a bus address. | ||
275 | */ | 294 | */ |
295 | |||
276 | struct CommandList { | 296 | struct CommandList { |
277 | struct CommandListHeader Header; | 297 | struct CommandListHeader Header; |
278 | struct RequestBlock Request; | 298 | struct RequestBlock Request; |
@@ -291,6 +311,14 @@ struct CommandList { | |||
291 | struct completion *waiting; | 311 | struct completion *waiting; |
292 | int retry_count; | 312 | int retry_count; |
293 | void *scsi_cmd; | 313 | void *scsi_cmd; |
314 | |||
315 | /* on 64 bit architectures, to get this to be 32-byte-aligned | ||
316 | * it so happens we need no padding, on 32 bit systems, | ||
317 | * we need 8 bytes of padding. This does that. | ||
318 | */ | ||
319 | #define COMMANDLIST_PAD ((8 - sizeof(long))/4 * 8) | ||
320 | u8 pad[COMMANDLIST_PAD]; | ||
321 | |||
294 | }; | 322 | }; |
295 | 323 | ||
296 | /* Configuration Table Structure */ | 324 | /* Configuration Table Structure */ |
@@ -301,18 +329,38 @@ struct HostWrite { | |||
301 | u32 CoalIntCount; | 329 | u32 CoalIntCount; |
302 | }; | 330 | }; |
303 | 331 | ||
332 | #define SIMPLE_MODE 0x02 | ||
333 | #define PERFORMANT_MODE 0x04 | ||
334 | #define MEMQ_MODE 0x08 | ||
335 | |||
304 | struct CfgTable { | 336 | struct CfgTable { |
305 | u8 Signature[4]; | 337 | u8 Signature[4]; |
306 | u32 SpecValence; | 338 | u32 SpecValence; |
307 | u32 TransportSupport; | 339 | u32 TransportSupport; |
308 | u32 TransportActive; | 340 | u32 TransportActive; |
309 | struct HostWrite HostWrite; | 341 | struct HostWrite HostWrite; |
310 | u32 CmdsOutMax; | 342 | u32 CmdsOutMax; |
311 | u32 BusTypes; | 343 | u32 BusTypes; |
312 | u32 Reserved; | 344 | u32 TransMethodOffset; |
313 | u8 ServerName[16]; | 345 | u8 ServerName[16]; |
314 | u32 HeartBeat; | 346 | u32 HeartBeat; |
315 | u32 SCSI_Prefetch; | 347 | u32 SCSI_Prefetch; |
348 | u32 MaxScatterGatherElements; | ||
349 | u32 MaxLogicalUnits; | ||
350 | u32 MaxPhysicalDevices; | ||
351 | u32 MaxPhysicalDrivesPerLogicalUnit; | ||
352 | u32 MaxPerformantModeCommands; | ||
353 | }; | ||
354 | |||
355 | #define NUM_BLOCKFETCH_ENTRIES 8 | ||
356 | struct TransTable_struct { | ||
357 | u32 BlockFetch[NUM_BLOCKFETCH_ENTRIES]; | ||
358 | u32 RepQSize; | ||
359 | u32 RepQCount; | ||
360 | u32 RepQCtrAddrLow32; | ||
361 | u32 RepQCtrAddrHigh32; | ||
362 | u32 RepQAddr0Low32; | ||
363 | u32 RepQAddr0High32; | ||
316 | }; | 364 | }; |
317 | 365 | ||
318 | struct hpsa_pci_info { | 366 | struct hpsa_pci_info { |