diff options
Diffstat (limited to 'drivers/scsi')
| -rw-r--r-- | drivers/scsi/hpsa.c | 134 | ||||
| -rw-r--r-- | drivers/scsi/hpsa.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/hpsa_cmd.h | 7 |
3 files changed, 131 insertions, 14 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2e1edce9b20e..183d3a43c280 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c | |||
| @@ -187,7 +187,6 @@ static struct scsi_host_template hpsa_driver_template = { | |||
| 187 | .scan_finished = hpsa_scan_finished, | 187 | .scan_finished = hpsa_scan_finished, |
| 188 | .change_queue_depth = hpsa_change_queue_depth, | 188 | .change_queue_depth = hpsa_change_queue_depth, |
| 189 | .this_id = -1, | 189 | .this_id = -1, |
| 190 | .sg_tablesize = MAXSGENTRIES, | ||
| 191 | .use_clustering = ENABLE_CLUSTERING, | 190 | .use_clustering = ENABLE_CLUSTERING, |
| 192 | .eh_device_reset_handler = hpsa_eh_device_reset_handler, | 191 | .eh_device_reset_handler = hpsa_eh_device_reset_handler, |
| 193 | .ioctl = hpsa_ioctl, | 192 | .ioctl = hpsa_ioctl, |
| @@ -844,6 +843,76 @@ static void hpsa_scsi_setup(struct ctlr_info *h) | |||
| 844 | spin_lock_init(&h->devlock); | 843 | spin_lock_init(&h->devlock); |
| 845 | } | 844 | } |
| 846 | 845 | ||
| 846 | static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) | ||
| 847 | { | ||
| 848 | int i; | ||
| 849 | |||
| 850 | if (!h->cmd_sg_list) | ||
| 851 | return; | ||
| 852 | for (i = 0; i < h->nr_cmds; i++) { | ||
| 853 | kfree(h->cmd_sg_list[i]); | ||
| 854 | h->cmd_sg_list[i] = NULL; | ||
| 855 | } | ||
| 856 | kfree(h->cmd_sg_list); | ||
| 857 | h->cmd_sg_list = NULL; | ||
| 858 | } | ||
| 859 | |||
| 860 | static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) | ||
| 861 | { | ||
| 862 | int i; | ||
| 863 | |||
| 864 | if (h->chainsize <= 0) | ||
| 865 | return 0; | ||
| 866 | |||
| 867 | h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds, | ||
| 868 | GFP_KERNEL); | ||
| 869 | if (!h->cmd_sg_list) | ||
| 870 | return -ENOMEM; | ||
| 871 | for (i = 0; i < h->nr_cmds; i++) { | ||
| 872 | h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) * | ||
| 873 | h->chainsize, GFP_KERNEL); | ||
| 874 | if (!h->cmd_sg_list[i]) | ||
| 875 | goto clean; | ||
| 876 | } | ||
| 877 | return 0; | ||
| 878 | |||
| 879 | clean: | ||
| 880 | hpsa_free_sg_chain_blocks(h); | ||
| 881 | return -ENOMEM; | ||
| 882 | } | ||
| 883 | |||
| 884 | static void hpsa_map_sg_chain_block(struct ctlr_info *h, | ||
| 885 | struct CommandList *c) | ||
| 886 | { | ||
| 887 | struct SGDescriptor *chain_sg, *chain_block; | ||
| 888 | u64 temp64; | ||
| 889 | |||
| 890 | chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; | ||
| 891 | chain_block = h->cmd_sg_list[c->cmdindex]; | ||
| 892 | chain_sg->Ext = HPSA_SG_CHAIN; | ||
| 893 | chain_sg->Len = sizeof(*chain_sg) * | ||
| 894 | (c->Header.SGTotal - h->max_cmd_sg_entries); | ||
| 895 | temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len, | ||
| 896 | PCI_DMA_TODEVICE); | ||
| 897 | chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL); | ||
| 898 | chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL); | ||
| 899 | } | ||
| 900 | |||
| 901 | static void hpsa_unmap_sg_chain_block(struct ctlr_info *h, | ||
| 902 | struct CommandList *c) | ||
| 903 | { | ||
| 904 | struct SGDescriptor *chain_sg; | ||
| 905 | union u64bit temp64; | ||
| 906 | |||
| 907 | if (c->Header.SGTotal <= h->max_cmd_sg_entries) | ||
| 908 | return; | ||
| 909 | |||
| 910 | chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; | ||
| 911 | temp64.val32.lower = chain_sg->Addr.lower; | ||
| 912 | temp64.val32.upper = chain_sg->Addr.upper; | ||
| 913 | pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE); | ||
| 914 | } | ||
| 915 | |||
| 847 | static void complete_scsi_command(struct CommandList *cp, | 916 | static void complete_scsi_command(struct CommandList *cp, |
| 848 | int timeout, u32 tag) | 917 | int timeout, u32 tag) |
| 849 | { | 918 | { |
| @@ -860,6 +929,8 @@ static void complete_scsi_command(struct CommandList *cp, | |||
| 860 | h = cp->h; | 929 | h = cp->h; |
| 861 | 930 | ||
| 862 | scsi_dma_unmap(cmd); /* undo the DMA mappings */ | 931 | scsi_dma_unmap(cmd); /* undo the DMA mappings */ |
| 932 | if (cp->Header.SGTotal > h->max_cmd_sg_entries) | ||
| 933 | hpsa_unmap_sg_chain_block(h, cp); | ||
| 863 | 934 | ||
| 864 | cmd->result = (DID_OK << 16); /* host byte */ | 935 | cmd->result = (DID_OK << 16); /* host byte */ |
| 865 | cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ | 936 | cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ |
| @@ -1064,6 +1135,7 @@ static int hpsa_scsi_detect(struct ctlr_info *h) | |||
| 1064 | sh->max_id = HPSA_MAX_LUN; | 1135 | sh->max_id = HPSA_MAX_LUN; |
| 1065 | sh->can_queue = h->nr_cmds; | 1136 | sh->can_queue = h->nr_cmds; |
| 1066 | sh->cmd_per_lun = h->nr_cmds; | 1137 | sh->cmd_per_lun = h->nr_cmds; |
| 1138 | sh->sg_tablesize = h->maxsgentries; | ||
| 1067 | h->scsi_host = sh; | 1139 | h->scsi_host = sh; |
| 1068 | sh->hostdata[0] = (unsigned long) h; | 1140 | sh->hostdata[0] = (unsigned long) h; |
| 1069 | sh->irq = h->intr[PERF_MODE_INT]; | 1141 | sh->irq = h->intr[PERF_MODE_INT]; |
| @@ -1765,16 +1837,17 @@ out: | |||
| 1765 | * dma mapping and fills in the scatter gather entries of the | 1837 | * dma mapping and fills in the scatter gather entries of the |
| 1766 | * hpsa command, cp. | 1838 | * hpsa command, cp. |
| 1767 | */ | 1839 | */ |
| 1768 | static int hpsa_scatter_gather(struct pci_dev *pdev, | 1840 | static int hpsa_scatter_gather(struct ctlr_info *h, |
| 1769 | struct CommandList *cp, | 1841 | struct CommandList *cp, |
| 1770 | struct scsi_cmnd *cmd) | 1842 | struct scsi_cmnd *cmd) |
| 1771 | { | 1843 | { |
| 1772 | unsigned int len; | 1844 | unsigned int len; |
| 1773 | struct scatterlist *sg; | 1845 | struct scatterlist *sg; |
| 1774 | u64 addr64; | 1846 | u64 addr64; |
| 1775 | int use_sg, i; | 1847 | int use_sg, i, sg_index, chained; |
| 1848 | struct SGDescriptor *curr_sg; | ||
| 1776 | 1849 | ||
| 1777 | BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES); | 1850 | BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); |
| 1778 | 1851 | ||
| 1779 | use_sg = scsi_dma_map(cmd); | 1852 | use_sg = scsi_dma_map(cmd); |
| 1780 | if (use_sg < 0) | 1853 | if (use_sg < 0) |
| @@ -1783,15 +1856,33 @@ static int hpsa_scatter_gather(struct pci_dev *pdev, | |||
| 1783 | if (!use_sg) | 1856 | if (!use_sg) |
| 1784 | goto sglist_finished; | 1857 | goto sglist_finished; |
| 1785 | 1858 | ||
| 1859 | curr_sg = cp->SG; | ||
| 1860 | chained = 0; | ||
| 1861 | sg_index = 0; | ||
| 1786 | scsi_for_each_sg(cmd, sg, use_sg, i) { | 1862 | scsi_for_each_sg(cmd, sg, use_sg, i) { |
| 1863 | if (i == h->max_cmd_sg_entries - 1 && | ||
| 1864 | use_sg > h->max_cmd_sg_entries) { | ||
| 1865 | chained = 1; | ||
| 1866 | curr_sg = h->cmd_sg_list[cp->cmdindex]; | ||
| 1867 | sg_index = 0; | ||
| 1868 | } | ||
| 1787 | addr64 = (u64) sg_dma_address(sg); | 1869 | addr64 = (u64) sg_dma_address(sg); |
| 1788 | len = sg_dma_len(sg); | 1870 | len = sg_dma_len(sg); |
| 1789 | cp->SG[i].Addr.lower = | 1871 | curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL); |
| 1790 | (u32) (addr64 & (u64) 0x00000000FFFFFFFF); | 1872 | curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL); |
| 1791 | cp->SG[i].Addr.upper = | 1873 | curr_sg->Len = len; |
| 1792 | (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF); | 1874 | curr_sg->Ext = 0; /* we are not chaining */ |
| 1793 | cp->SG[i].Len = len; | 1875 | curr_sg++; |
| 1794 | cp->SG[i].Ext = 0; /* we are not chaining */ | 1876 | } |
| 1877 | |||
| 1878 | if (use_sg + chained > h->maxSG) | ||
| 1879 | h->maxSG = use_sg + chained; | ||
| 1880 | |||
| 1881 | if (chained) { | ||
| 1882 | cp->Header.SGList = h->max_cmd_sg_entries; | ||
| 1883 | cp->Header.SGTotal = (u16) (use_sg + 1); | ||
| 1884 | hpsa_map_sg_chain_block(h, cp); | ||
| 1885 | return 0; | ||
| 1795 | } | 1886 | } |
| 1796 | 1887 | ||
| 1797 | sglist_finished: | 1888 | sglist_finished: |
| @@ -1887,7 +1978,7 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd, | |||
| 1887 | break; | 1978 | break; |
| 1888 | } | 1979 | } |
| 1889 | 1980 | ||
| 1890 | if (hpsa_scatter_gather(h->pdev, c, cmd) < 0) { /* Fill SG list */ | 1981 | if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */ |
| 1891 | cmd_free(h, c); | 1982 | cmd_free(h, c); |
| 1892 | return SCSI_MLQUEUE_HOST_BUSY; | 1983 | return SCSI_MLQUEUE_HOST_BUSY; |
| 1893 | } | 1984 | } |
| @@ -3283,6 +3374,23 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) | |||
| 3283 | 3374 | ||
| 3284 | h->board_id = board_id; | 3375 | h->board_id = board_id; |
| 3285 | h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); | 3376 | h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); |
| 3377 | h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); | ||
| 3378 | |||
| 3379 | /* | ||
| 3380 | * Limit in-command s/g elements to 32 save dma'able memory. | ||
| 3381 | * Howvever spec says if 0, use 31 | ||
| 3382 | */ | ||
| 3383 | |||
| 3384 | h->max_cmd_sg_entries = 31; | ||
| 3385 | if (h->maxsgentries > 512) { | ||
| 3386 | h->max_cmd_sg_entries = 32; | ||
| 3387 | h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1; | ||
| 3388 | h->maxsgentries--; /* save one for chain pointer */ | ||
| 3389 | } else { | ||
| 3390 | h->maxsgentries = 31; /* default to traditional values */ | ||
| 3391 | h->chainsize = 0; | ||
| 3392 | } | ||
| 3393 | |||
| 3286 | h->product_name = products[prod_index].product_name; | 3394 | h->product_name = products[prod_index].product_name; |
| 3287 | h->access = *(products[prod_index].access); | 3395 | h->access = *(products[prod_index].access); |
| 3288 | /* Allow room for some ioctls */ | 3396 | /* Allow room for some ioctls */ |
| @@ -3463,6 +3571,8 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, | |||
| 3463 | rc = -ENOMEM; | 3571 | rc = -ENOMEM; |
| 3464 | goto clean4; | 3572 | goto clean4; |
| 3465 | } | 3573 | } |
| 3574 | if (hpsa_allocate_sg_chain_blocks(h)) | ||
| 3575 | goto clean4; | ||
| 3466 | spin_lock_init(&h->lock); | 3576 | spin_lock_init(&h->lock); |
| 3467 | spin_lock_init(&h->scan_lock); | 3577 | spin_lock_init(&h->scan_lock); |
| 3468 | init_waitqueue_head(&h->scan_wait_queue); | 3578 | init_waitqueue_head(&h->scan_wait_queue); |
| @@ -3485,6 +3595,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, | |||
| 3485 | return 1; | 3595 | return 1; |
| 3486 | 3596 | ||
| 3487 | clean4: | 3597 | clean4: |
| 3598 | hpsa_free_sg_chain_blocks(h); | ||
| 3488 | kfree(h->cmd_pool_bits); | 3599 | kfree(h->cmd_pool_bits); |
| 3489 | if (h->cmd_pool) | 3600 | if (h->cmd_pool) |
| 3490 | pci_free_consistent(h->pdev, | 3601 | pci_free_consistent(h->pdev, |
| @@ -3560,6 +3671,7 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev) | |||
| 3560 | hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ | 3671 | hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ |
| 3561 | hpsa_shutdown(pdev); | 3672 | hpsa_shutdown(pdev); |
| 3562 | iounmap(h->vaddr); | 3673 | iounmap(h->vaddr); |
| 3674 | hpsa_free_sg_chain_blocks(h); | ||
| 3563 | pci_free_consistent(h->pdev, | 3675 | pci_free_consistent(h->pdev, |
| 3564 | h->nr_cmds * sizeof(struct CommandList), | 3676 | h->nr_cmds * sizeof(struct CommandList), |
| 3565 | h->cmd_pool, h->cmd_pool_dhandle); | 3677 | h->cmd_pool, h->cmd_pool_dhandle); |
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index fc15215145d9..1bb5233b09a0 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h | |||
| @@ -83,6 +83,10 @@ struct ctlr_info { | |||
| 83 | unsigned int maxQsinceinit; | 83 | unsigned int maxQsinceinit; |
| 84 | unsigned int maxSG; | 84 | unsigned int maxSG; |
| 85 | spinlock_t lock; | 85 | spinlock_t lock; |
| 86 | int maxsgentries; | ||
| 87 | u8 max_cmd_sg_entries; | ||
| 88 | int chainsize; | ||
| 89 | struct SGDescriptor **cmd_sg_list; | ||
| 86 | 90 | ||
| 87 | /* pointers to command and error info pool */ | 91 | /* pointers to command and error info pool */ |
| 88 | struct CommandList *cmd_pool; | 92 | struct CommandList *cmd_pool; |
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 43b6f1cffe34..cb0c2385f3f6 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h | |||
| @@ -23,7 +23,8 @@ | |||
| 23 | 23 | ||
| 24 | /* general boundary defintions */ | 24 | /* general boundary defintions */ |
| 25 | #define SENSEINFOBYTES 32 /* may vary between hbas */ | 25 | #define SENSEINFOBYTES 32 /* may vary between hbas */ |
| 26 | #define MAXSGENTRIES 31 | 26 | #define MAXSGENTRIES 32 |
| 27 | #define HPSA_SG_CHAIN 0x80000000 | ||
| 27 | #define MAXREPLYQS 256 | 28 | #define MAXREPLYQS 256 |
| 28 | 29 | ||
| 29 | /* Command Status value */ | 30 | /* Command Status value */ |
| @@ -321,8 +322,8 @@ struct CommandList { | |||
| 321 | */ | 322 | */ |
| 322 | #define IS_32_BIT ((8 - sizeof(long))/4) | 323 | #define IS_32_BIT ((8 - sizeof(long))/4) |
| 323 | #define IS_64_BIT (!IS_32_BIT) | 324 | #define IS_64_BIT (!IS_32_BIT) |
| 324 | #define PAD_32 (8) | 325 | #define PAD_32 (24) |
| 325 | #define PAD_64 (0) | 326 | #define PAD_64 (16) |
| 326 | #define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64) | 327 | #define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64) |
| 327 | u8 pad[COMMANDLIST_PAD]; | 328 | u8 pad[COMMANDLIST_PAD]; |
| 328 | }; | 329 | }; |
