+ sz = ioc->num_fw_frags * sizeof(void *);
+ mem = kmalloc(sz, GFP_ATOMIC);
+ if (mem == NULL)
+ return NULL;
+
+ memset(mem, 0, sz);
+ cached_fw = (fw_image_t **)mem;
+ alloc_total += sz;
+
+ /* malloc fragment memory
+ * fw_image_t struct and dma for fw data
+ */
+ bytes_left = size;
+ ii = 0;
+ num_frags = 0;
+ bytes = bytes_left;
+ while((bytes_left) && (num_frags < ioc->num_fw_frags)) {
+ if (cached_fw[ii] == NULL) {
+ mem = kmalloc(sizeof(fw_image_t), GFP_ATOMIC);
+ if (mem == NULL)
+ break;
+
+ memset(mem, 0, sizeof(fw_image_t));
+ cached_fw[ii] = (fw_image_t *)mem;
+ alloc_total += sizeof(fw_image_t);
+ }
+
+ mem = pci_alloc_consistent(ioc->pcidev, bytes, &fw_dma);
+ if (mem == NULL) {
+ if (bytes > 0x10000)
+ bytes = 0x10000;
+ else if (bytes > 0x8000)
+ bytes = 0x8000;
+ else if (bytes > 0x4000)
+ bytes = 0x4000;
+ else if (bytes > 0x2000)
+ bytes = 0x2000;
+ else if (bytes > 0x1000)
+ bytes = 0x1000;
+ else
+ break;
+
+ continue;
+ }
+
+ cached_fw[ii]->fw = mem;
+ cached_fw[ii]->fw_dma = fw_dma;
+ cached_fw[ii]->size = bytes;
+ memset(mem, 0, bytes);
+ alloc_total += bytes;
+
+ bytes_left -= bytes;
+
+ num_frags++;
+ ii++;
+ }
+
+ if (bytes_left ) {
+ /* Major Failure.
+ */
+ mpt_free_fw_memory(ioc, cached_fw);
+ return NULL;
+ }
+
+ *frags = num_frags;
+ *alloc_sz = alloc_total;