hlist_del_init(&c->list);
}
+static void cciss_free_sg_chain_blocks(SGDescriptor_struct **cmd_sg_list,
+ int nr_cmds)
+{
+ int i;
+
+ if (!cmd_sg_list)
+ return;
+ for (i = 0; i < nr_cmds; i++) {
+ kfree(cmd_sg_list[i]);
+ cmd_sg_list[i] = NULL;
+ }
+ kfree(cmd_sg_list);
+}
+
+static SGDescriptor_struct **cciss_allocate_sg_chain_blocks(
+ ctlr_info_t *h, int chainsize, int nr_cmds)
+{
+ int j;
+ SGDescriptor_struct **cmd_sg_list;
+
+ if (chainsize <= 0)
+ return NULL;
+
+ cmd_sg_list = kmalloc(sizeof(*cmd_sg_list) * nr_cmds, GFP_KERNEL);
+ if (!cmd_sg_list)
+ return NULL;
+
+ /* Build up chain blocks for each command */
+ for (j = 0; j < nr_cmds; j++) {
+ /* Need a block of chainsized s/g elements. */
+ cmd_sg_list[j] = kmalloc((chainsize *
+ sizeof(*cmd_sg_list[j])), GFP_KERNEL);
+ if (!cmd_sg_list[j]) {
+ dev_err(&h->pdev->dev, "Cannot get memory "
+ "for s/g chains.\n");
+ goto clean;
+ }
+ }
+ return cmd_sg_list;
+clean:
+ cciss_free_sg_chain_blocks(cmd_sg_list, nr_cmds);
+ return NULL;
+}
+
+static void cciss_unmap_sg_chain_block(ctlr_info_t *h, CommandList_struct *c)
+{
+ SGDescriptor_struct *chain_sg;
+ u64bit temp64;
+
+ if (c->Header.SGTotal <= h->max_cmd_sgentries)
+ return;
+
+ chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+ temp64.val32.lower = chain_sg->Addr.lower;
+ temp64.val32.upper = chain_sg->Addr.upper;
+ pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
+}
+
+static void cciss_map_sg_chain_block(ctlr_info_t *h, CommandList_struct *c,
+ SGDescriptor_struct *chain_block, int len)
+{
+ SGDescriptor_struct *chain_sg;
+ u64bit temp64;
+
+ chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+ chain_sg->Ext = CCISS_SG_CHAIN;
+ chain_sg->Len = len;
+ temp64.val = pci_map_single(h->pdev, chain_block, len,
+ PCI_DMA_TODEVICE);
+ chain_sg->Addr.lower = temp64.val32.lower;
+ chain_sg->Addr.upper = temp64.val32.upper;
+}
+
#include "cciss_scsi.c" /* For SCSI tape support */
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
/* unmap the DMA mapping for all the scatter gather elements */
for (i = 0; i < cmd->Header.SGList; i++) {
if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
- temp64.val32.lower = cmd->SG[i].Addr.lower;
- temp64.val32.upper = cmd->SG[i].Addr.upper;
- pci_dma_sync_single_for_cpu(h->pdev, temp64.val,
- cmd->SG[i].Len, ddir);
- pci_unmap_single(h->pdev, temp64.val,
- cmd->SG[i].Len, ddir);
+ cciss_unmap_sg_chain_block(h, cmd);
/* Point to the next block */
- curr_sg = h->cmd_sg_list[cmd->cmdindex]->sgchain;
+ curr_sg = h->cmd_sg_list[cmd->cmdindex];
sg_index = 0;
}
temp64.val32.lower = curr_sg[sg_index].Addr.lower;
SGDescriptor_struct *curr_sg;
drive_info_struct *drv;
int i, dir;
- int nseg = 0;
int sg_index = 0;
int chained = 0;
for (i = 0; i < seg; i++) {
if (((sg_index+1) == (h->max_cmd_sgentries)) &&
!chained && ((seg - i) > 1)) {
- nseg = seg - i;
- curr_sg[sg_index].Len = (nseg) *
- sizeof(SGDescriptor_struct);
- curr_sg[sg_index].Ext = CCISS_SG_CHAIN;
-
/* Point to next chain block. */
- curr_sg = h->cmd_sg_list[c->cmdindex]->sgchain;
+ curr_sg = h->cmd_sg_list[c->cmdindex];
sg_index = 0;
chained = 1;
}
curr_sg[sg_index].Addr.lower = temp64.val32.lower;
curr_sg[sg_index].Addr.upper = temp64.val32.upper;
curr_sg[sg_index].Ext = 0; /* we are not chaining */
-
++sg_index;
}
-
- if (chained) {
- int len;
- curr_sg = c->SG;
- sg_index = h->max_cmd_sgentries - 1;
- len = curr_sg[sg_index].Len;
- /* Setup pointer to next chain block.
- * Fill out last element in current chain
- * block with address of next chain block.
- */
- temp64.val = pci_map_single(h->pdev,
- h->cmd_sg_list[c->cmdindex]->sgchain,
- len, dir);
-
- h->cmd_sg_list[c->cmdindex]->sg_chain_dma = temp64.val;
- curr_sg[sg_index].Addr.lower = temp64.val32.lower;
- curr_sg[sg_index].Addr.upper = temp64.val32.upper;
-
- pci_dma_sync_single_for_device(h->pdev,
- h->cmd_sg_list[c->cmdindex]->sg_chain_dma,
- len, dir);
- }
+ if (chained)
+ cciss_map_sg_chain_block(h, c, h->cmd_sg_list[c->cmdindex],
+ (seg - (h->max_cmd_sgentries - 1)) *
+ sizeof(SGDescriptor_struct));
/* track how many SG entries we are using */
if (seg > h->maxSG)
goto clean4;
}
}
- hba[i]->cmd_sg_list = kmalloc(sizeof(struct Cmd_sg_list *) *
- hba[i]->nr_cmds,
- GFP_KERNEL);
- if (!hba[i]->cmd_sg_list) {
- printk(KERN_ERR "cciss%d: Cannot get memory for "
- "s/g chaining.\n", i);
+ hba[i]->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[i],
+ hba[i]->chainsize, hba[i]->nr_cmds);
+ if (!hba[i]->cmd_sg_list && hba[i]->chainsize > 0)
goto clean4;
- }
- /* Build up chain blocks for each command */
- if (hba[i]->chainsize > 0) {
- for (j = 0; j < hba[i]->nr_cmds; j++) {
- hba[i]->cmd_sg_list[j] =
- kmalloc(sizeof(struct Cmd_sg_list),
- GFP_KERNEL);
- if (!hba[i]->cmd_sg_list[j]) {
- printk(KERN_ERR "cciss%d: Cannot get memory "
- "for chain block.\n", i);
- goto clean4;
- }
- /* Need a block of chainsized s/g elements. */
- hba[i]->cmd_sg_list[j]->sgchain =
- kmalloc((hba[i]->chainsize *
- sizeof(SGDescriptor_struct)),
- GFP_KERNEL);
- if (!hba[i]->cmd_sg_list[j]->sgchain) {
- printk(KERN_ERR "cciss%d: Cannot get memory "
- "for s/g chains\n", i);
- goto clean4;
- }
- }
- }
spin_lock_init(&hba[i]->lock);
for (k = 0; k < hba[i]->nr_cmds; k++)
kfree(hba[i]->scatter_list[k]);
kfree(hba[i]->scatter_list);
- /* Only free up extra s/g lists if controller supports them */
- if (hba[i]->chainsize > 0) {
- for (j = 0; j < hba[i]->nr_cmds; j++) {
- if (hba[i]->cmd_sg_list[j]) {
- kfree(hba[i]->cmd_sg_list[j]->sgchain);
- kfree(hba[i]->cmd_sg_list[j]);
- }
- }
- kfree(hba[i]->cmd_sg_list);
- }
+ cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
if (hba[i]->cmd_pool)
pci_free_consistent(hba[i]->pdev,
hba[i]->nr_cmds * sizeof(CommandList_struct),
for (j = 0; j < hba[i]->nr_cmds; j++)
kfree(hba[i]->scatter_list[j]);
kfree(hba[i]->scatter_list);
- /* Only free up extra s/g lists if controller supports them */
- if (hba[i]->chainsize > 0) {
- for (j = 0; j < hba[i]->nr_cmds; j++) {
- if (hba[i]->cmd_sg_list[j]) {
- kfree(hba[i]->cmd_sg_list[j]->sgchain);
- kfree(hba[i]->cmd_sg_list[j]);
- }
- }
- kfree(hba[i]->cmd_sg_list);
- }
+ cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo