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.c | |
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.c')
-rw-r--r-- | drivers/scsi/hpsa.c | 286 |
1 files changed, 241 insertions, 45 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. |