/** * megaraid_init - module load hook * * We register ourselves as hotplug enabled module and let PCI subsystem * discover our adapters. */ static int __init megaraid_init(void) { int rval; // Announce the driver version con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION, MEGARAID_EXT_VERSION)); // check validity of module parameters if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) { con_log(CL_ANN, (KERN_WARNING "megaraid mailbox: max commands per lun reset to %d\n", MBOX_MAX_SCSI_CMDS)); megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS; } // register as a PCI hot-plug driver module rval = pci_register_driver(&megaraid_pci_driver); if (rval < 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not register hotplug support.\n")); } return rval; }
/** * megaraid_detach_one - release framework resources and call LLD release routine * @pdev : handle for our PCI configuration space * * This routine is called during driver unload. We free all the allocated * resources and call the corresponding LLD so that it can also release all * its resources. * * This routine is also called from the PCI hotplug system. */ static void megaraid_detach_one(struct pci_dev *pdev) { adapter_t *adapter; struct Scsi_Host *host; // Start a rollback on this adapter adapter = pci_get_drvdata(pdev); if (!adapter) { con_log(CL_ANN, (KERN_CRIT "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device)); return; } else { con_log(CL_ANN, (KERN_NOTICE "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device)); } host = adapter->host; // do not allow any more requests from the management module for this // adapter. // FIXME: How do we account for the request which might still be // pending with us? atomic_set(&adapter->being_detached, 1); // detach from the IO sub-system megaraid_io_detach(adapter); // Unregister from common management module // // FIXME: this must return success or failure for conditions if there // is a command pending with LLD or not. megaraid_cmm_unregister(adapter); // finalize the mailbox based controller and release all resources megaraid_fini_mbox(adapter); kfree(adapter); scsi_host_put(host); pci_disable_device(pdev); return; }
void mr_update_load_balance_params(MR_FW_RAID_MAP_ALL *map, PLD_LOAD_BALANCE_INFO lbInfo) { int ldCount; U16 ld; MR_LD_RAID *raid; for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) { ld = MR_TargetIdToLdGet(ldCount, map); if (ld >= MAX_LOGICAL_DRIVES) { con_log(CL_ANN1, (CE_NOTE, "mrsas: ld=%d Invalid ld \n", ld)); continue; } raid = MR_LdRaidGet(ld, map); /* Two drive Optimal RAID 1 */ if ((raid->level == 1) && (raid->rowSize == 2) && (raid->spanDepth == 1) && raid->ldState == MR_LD_STATE_OPTIMAL) { U32 pd, arRef; lbInfo[ldCount].loadBalanceFlag = 1; /* Get the array on which this span is present. */ arRef = MR_LdSpanArrayGet(ld, 0, map); pd = MR_ArPdGet(arRef, 0, map); /* Get the Pd. */ /* Get dev handle from Pd. */ lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map); pd = MR_ArPdGet(arRef, 1, map); /* Get the Pd. */ /* Get dev handle from Pd. */ lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map); con_log(CL_ANN1, (CE_NOTE, "mrsas: ld=%d load balancing enabled \n", ldCount)); } else { lbInfo[ldCount].loadBalanceFlag = 0; } } }
/** * megaraid_io_attach - attach a device with the IO subsystem * @adapter : controller's soft state * * Attach this device with the IO subsystem. */ static int megaraid_io_attach(adapter_t *adapter) { struct Scsi_Host *host; // Initialize SCSI Host structure host = scsi_host_alloc(&megaraid_template_g, 8); if (!host) { con_log(CL_ANN, (KERN_WARNING "megaraid mbox: scsi_register failed\n")); return -1; } SCSIHOST2ADAP(host) = (caddr_t)adapter; adapter->host = host; host->irq = adapter->irq; host->unique_id = adapter->unique_id; host->can_queue = adapter->max_cmds; host->this_id = adapter->init_id; host->sg_tablesize = adapter->sglen; host->max_sectors = adapter->max_sectors; host->cmd_per_lun = adapter->cmd_per_lun; host->max_channel = adapter->max_channel; host->max_id = adapter->max_target; host->max_lun = adapter->max_lun; // notify mid-layer about the new controller if (scsi_add_host(host, &adapter->pdev->dev)) { con_log(CL_ANN, (KERN_WARNING "megaraid mbox: scsi_add_host failed\n")); scsi_host_put(host); return -1; } scsi_scan_host(host); return 0; }
/** * megaraid_exit - driver unload entry point * * We simply unwrap the megaraid_init routine here. */ static void __exit megaraid_exit(void) { con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); // unregister as PCI hotplug driver pci_unregister_driver(&megaraid_pci_driver); return; }
/** * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA * @pdev : generic driver model device * * Shutdown notification, perform flush cache. */ static void megaraid_mbox_shutdown(struct pci_dev *pdev) { adapter_t *adapter = pci_get_drvdata(pdev); static int counter; if (!adapter) { con_log(CL_ANN, (KERN_WARNING "megaraid: null device in shutdown\n")); return; } // flush caches now con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...", counter++)); megaraid_mbox_flush_cache(adapter); con_log(CL_ANN, ("done\n")); }
/** * megaraid_io_detach - detach a device from the IO subsystem * @adapter : controller's soft state * * Detach this device from the IO subsystem. */ static void megaraid_io_detach(adapter_t *adapter) { struct Scsi_Host *host; con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n")); host = adapter->host; scsi_remove_host(host); return; }
/* * This function will validate Map info data provided by FW */ U8 MR_ValidateMapInfo(MR_FW_RAID_MAP_ALL *map, PLD_LOAD_BALANCE_INFO lbInfo) { MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap; U32 fwsize = sizeof (MR_FW_RAID_MAP) - sizeof (MR_LD_SPAN_MAP) + (sizeof (MR_LD_SPAN_MAP) * pFwRaidMap->ldCount); if (pFwRaidMap->totalSize != fwsize) { con_log(CL_ANN1, (CE_NOTE, "map info structure size 0x%x is " "not matching with ld count\n", fwsize)); /* sizeof (foo) returns size_t, which is *LONG*. */ con_log(CL_ANN1, (CE_NOTE, "span map 0x%x total size 0x%x\n",\ (int)sizeof (MR_LD_SPAN_MAP), pFwRaidMap->totalSize)); return (0); } mr_update_load_balance_params(map, lbInfo); return (1); }
/** * megaraid_alloc_cmd_packets - allocate shared mailbox * @adapter : soft state of the raid controller * * Allocate and align the shared mailbox. This maibox is used to issue * all the commands. For IO based controllers, the mailbox is also registered * with the FW. Allocate memory for all commands as well. * This is our big allocator. */ static int megaraid_alloc_cmd_packets(adapter_t *adapter) { mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); struct pci_dev *pdev; unsigned long align; scb_t *scb; mbox_ccb_t *ccb; struct mraid_pci_blk *epthru_pci_blk; struct mraid_pci_blk *sg_pci_blk; struct mraid_pci_blk *mbox_pci_blk; int i; pdev = adapter->pdev; /* * Setup the mailbox * Allocate the common 16-byte aligned memory for the handshake * mailbox. */ raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev, sizeof(mbox64_t), &raid_dev->una_mbox64_dma); if (!raid_dev->una_mbox64) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __func__, __LINE__)); return -1; } memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t)); /* * Align the mailbox at 16-byte boundary */ raid_dev->mbox = &raid_dev->una_mbox64->mbox32; raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) & (~0UL ^ 0xFUL)); raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8); align = ((void *)raid_dev->mbox - ((void *)&raid_dev->una_mbox64->mbox32)); raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 + align; // Allocate memory for commands issued internally adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE, &adapter->ibuf_dma_h); if (!adapter->ibuf) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __func__, __LINE__)); goto out_free_common_mbox; } memset(adapter->ibuf, 0, MBOX_IBUF_SIZE); // Allocate memory for our SCSI Command Blocks and their associated // memory /* * Allocate memory for the base list of scb. Later allocate memory for * CCBs and embedded components of each CCB and point the pointers in * scb to the allocated components * NOTE: The code to allocate SCB will be duplicated in all the LLD * since the calling routine does not yet know the number of available * commands. */ adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL); if (adapter->kscb_list == NULL) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __func__, __LINE__)); goto out_free_ibuf; } // memory allocation for our command packets if (megaraid_mbox_setup_dma_pools(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __func__, __LINE__)); goto out_free_scb_list; } // Adjust the scb pointers and link in the free pool epthru_pci_blk = raid_dev->epthru_pool; sg_pci_blk = raid_dev->sg_pool; mbox_pci_blk = raid_dev->mbox_pool; for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { scb = adapter->kscb_list + i; ccb = raid_dev->ccb_list + i; ccb->mbox = (mbox_t *)(mbox_pci_blk[i].vaddr + 16); ccb->raw_mbox = (uint8_t *)ccb->mbox; ccb->mbox64 = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8); ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16; // make sure the mailbox is aligned properly if (ccb->mbox_dma_h & 0x0F) { con_log(CL_ANN, (KERN_CRIT "megaraid mbox: not aligned on 16-bytes\n")); goto out_teardown_dma_pools; } ccb->epthru = (mraid_epassthru_t *) epthru_pci_blk[i].vaddr; ccb->epthru_dma_h = epthru_pci_blk[i].dma_addr; ccb->pthru = (mraid_passthru_t *)ccb->epthru; ccb->pthru_dma_h = ccb->epthru_dma_h; ccb->sgl64 = (mbox_sgl64 *)sg_pci_blk[i].vaddr; ccb->sgl_dma_h = sg_pci_blk[i].dma_addr; ccb->sgl32 = (mbox_sgl32 *)ccb->sgl64; scb->ccb = (caddr_t)ccb; scb->gp = 0; scb->sno = i; // command index scb->scp = NULL; scb->state = SCB_FREE; scb->dma_direction = PCI_DMA_NONE; scb->dma_type = MRAID_DMA_NONE; scb->dev_channel = -1; scb->dev_target = -1; // put scb in the free pool list_add_tail(&scb->list, &adapter->kscb_pool); } return 0; out_teardown_dma_pools: megaraid_mbox_teardown_dma_pools(adapter); out_free_scb_list: kfree(adapter->kscb_list); out_free_ibuf: pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, adapter->ibuf_dma_h); out_free_common_mbox: pci_free_consistent(adapter->pdev, sizeof(mbox64_t), (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); return -1; }
/** * megaraid_init_mbox - initialize controller * @adapter : our soft state * * - Allocate 16-byte aligned mailbox memory for firmware handshake * - Allocate controller's memory resources * - Find out all initialization data * - Allocate memory required for all the commands * - Use internal library of FW routines, build up complete soft state */ static int megaraid_init_mbox(adapter_t *adapter) { struct pci_dev *pdev; mraid_device_t *raid_dev; int i; uint32_t magic64; adapter->ito = MBOX_TIMEOUT; pdev = adapter->pdev; /* * Allocate and initialize the init data structure for mailbox * controllers */ raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL); if (raid_dev == NULL) return -1; /* * Attach the adapter soft state to raid device soft state */ adapter->raid_device = (caddr_t)raid_dev; raid_dev->fast_load = megaraid_fast_load; // our baseport raid_dev->baseport = pci_resource_start(pdev, 0); if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: mem region busy\n")); goto out_free_raid_dev; } raid_dev->baseaddr = ioremap_nocache(raid_dev->baseport, 128); if (!raid_dev->baseaddr) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not map hba memory\n") ); goto out_release_regions; } /* initialize the mutual exclusion lock for the mailbox */ spin_lock_init(&raid_dev->mailbox_lock); /* allocate memory required for commands */ if (megaraid_alloc_cmd_packets(adapter) != 0) goto out_iounmap; /* * Issue SYNC cmd to flush the pending cmds in the adapter * and initialize its internal state */ if (megaraid_mbox_fire_sync_cmd(adapter)) con_log(CL_ANN, ("megaraid: sync cmd failed\n")); /* * Setup the rest of the soft state using the library of * FW routines */ /* request IRQ and register the interrupt service routine */ if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid", adapter)) { con_log(CL_ANN, (KERN_WARNING "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); goto out_alloc_cmds; } // Product info if (megaraid_mbox_product_info(adapter) != 0) goto out_free_irq; // Do we support extended CDBs adapter->max_cdb_sz = 10; if (megaraid_mbox_extended_cdb(adapter) == 0) { adapter->max_cdb_sz = 16; } /* * Do we support cluster environment, if we do, what is the initiator * id. * NOTE: In a non-cluster aware firmware environment, the LLD should * return 7 as initiator id. */ adapter->ha = 0; adapter->init_id = -1; if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) { adapter->ha = 1; } /* * Prepare the device ids array to have the mapping between the kernel * device address and megaraid device address. * We export the physical devices on their actual addresses. The * logical drives are exported on a virtual SCSI channel */ megaraid_mbox_setup_device_map(adapter); // If the firmware supports random deletion, update the device id map if (megaraid_mbox_support_random_del(adapter)) { // Change the logical drives numbers in device_ids array one // slot in device_ids is reserved for target id, that's why // "<=" below for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) { adapter->device_ids[adapter->max_channel][i] += 0x80; } adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF; raid_dev->random_del_supported = 1; } /* * find out the maximum number of scatter-gather elements supported by * this firmware */ adapter->sglen = megaraid_mbox_get_max_sg(adapter); // enumerate RAID and SCSI channels so that all devices on SCSI // channels can later be exported, including disk devices megaraid_mbox_enum_raid_scsi(adapter); /* * Other parameters required by upper layer * * maximum number of sectors per IO command */ adapter->max_sectors = megaraid_max_sectors; /* * number of queued commands per LUN. */ adapter->cmd_per_lun = megaraid_cmd_per_lun; /* * Allocate resources required to issue FW calls, when sysfs is * accessed */ if (megaraid_sysfs_alloc_resources(adapter) != 0) goto out_free_irq; // Set the DMA mask to 64-bit. All supported controllers as capable of // DMA in this range pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64); if (((magic64 == HBA_SIGNATURE_64_BIT) && ((adapter->pdev->subsystem_device != PCI_SUBSYS_ID_MEGARAID_SATA_150_6) && (adapter->pdev->subsystem_device != PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) || (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && adapter->pdev->device == PCI_DEVICE_ID_VERDE) || (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && adapter->pdev->device == PCI_DEVICE_ID_DOBSON) || (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) || (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) || (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) { if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(64))) { con_log(CL_ANN, (KERN_WARNING "megaraid: DMA mask for 64-bit failed\n")); if (pci_set_dma_mask (adapter->pdev, DMA_BIT_MASK(32))) { con_log(CL_ANN, (KERN_WARNING "megaraid: 32-bit DMA mask failed\n")); goto out_free_sysfs_res; } } } // setup tasklet for DPC tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc, (unsigned long)adapter); con_log(CL_DLEVEL1, (KERN_INFO "megaraid mbox hba successfully initialized\n")); return 0; out_free_sysfs_res: megaraid_sysfs_free_resources(adapter); out_free_irq: free_irq(adapter->irq, adapter); out_alloc_cmds: megaraid_free_cmd_packets(adapter); out_iounmap: iounmap(raid_dev->baseaddr); out_release_regions: pci_release_regions(pdev); out_free_raid_dev: kfree(raid_dev); return -1; }
/** * megaraid_probe_one - PCI hotplug entry point * @pdev : handle to this controller's PCI configuration space * @id : pci device id of the class of controllers * * This routine should be called whenever a new adapter is detected by the * PCI hotplug susbsystem. */ static int megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { adapter_t *adapter; // detected a new controller con_log(CL_ANN, (KERN_INFO "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device)); con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); if (pci_enable_device(pdev)) { con_log(CL_ANN, (KERN_WARNING "megaraid: pci_enable_device failed\n")); return -ENODEV; } // Enable bus-mastering on this controller pci_set_master(pdev); // Allocate the per driver initialization structure adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL); if (adapter == NULL) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d.\n", __func__, __LINE__)); goto out_probe_one; } // set up PCI related soft state and other pre-known parameters adapter->unique_id = pdev->bus->number << 8 | pdev->devfn; adapter->irq = pdev->irq; adapter->pdev = pdev; atomic_set(&adapter->being_detached, 0); // Setup the default DMA mask. This would be changed later on // depending on hardware capabilities if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(32)) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: pci_set_dma_mask failed:%d\n", __LINE__)); goto out_free_adapter; } // Initialize the synchronization lock for kernel and LLD spin_lock_init(&adapter->lock); // Initialize the command queues: the list of free SCBs and the list // of pending SCBs. INIT_LIST_HEAD(&adapter->kscb_pool); spin_lock_init(SCSI_FREE_LIST_LOCK(adapter)); INIT_LIST_HEAD(&adapter->pend_list); spin_lock_init(PENDING_LIST_LOCK(adapter)); INIT_LIST_HEAD(&adapter->completed_list); spin_lock_init(COMPLETED_LIST_LOCK(adapter)); // Start the mailbox based controller if (megaraid_init_mbox(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: maibox adapter did not initialize\n")); goto out_free_adapter; } // Register with LSI Common Management Module if (megaraid_cmm_register(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not register with management module\n")); goto out_fini_mbox; } // setup adapter handle in PCI soft state pci_set_drvdata(pdev, adapter); // attach with scsi mid-layer if (megaraid_io_attach(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n")); goto out_cmm_unreg; } return 0; out_cmm_unreg: megaraid_cmm_unregister(adapter); out_fini_mbox: megaraid_fini_mbox(adapter); out_free_adapter: kfree(adapter); out_probe_one: pci_disable_device(pdev); return -ENODEV; }