summaryrefslogtreecommitdiff
path: root/drivers/scsi/pm8001
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/pm8001')
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c151
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c69
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c79
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c43
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h2
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c48
6 files changed, 221 insertions, 171 deletions
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index a368d77b8d41..7abbf284da1a 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -397,7 +397,10 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
payload.func_specific = kzalloc(4096, GFP_KERNEL);
if (!payload.func_specific)
return -ENOMEM;
- PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
+ if (PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload)) {
+ kfree(payload.func_specific);
+ return -ENOMEM;
+ }
wait_for_completion(&completion);
virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr;
for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT;
@@ -523,18 +526,19 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
{
struct pm8001_ioctl_payload *payload;
DECLARE_COMPLETION_ONSTACK(completion);
- u8 *ioctlbuffer = NULL;
- u32 length = 0;
- u32 ret = 0;
+ u8 *ioctlbuffer;
+ u32 ret;
+ u32 length = 1024 * 5 + sizeof(*payload) - 1;
+
+ if (pm8001_ha->fw_image->size > 4096) {
+ pm8001_ha->fw_status = FAIL_FILE_SIZE;
+ return -EFAULT;
+ }
- length = 1024 * 5 + sizeof(*payload) - 1;
ioctlbuffer = kzalloc(length, GFP_KERNEL);
- if (!ioctlbuffer)
+ if (!ioctlbuffer) {
+ pm8001_ha->fw_status = FAIL_OUT_MEMORY;
return -ENOMEM;
- if ((pm8001_ha->fw_image->size <= 0) ||
- (pm8001_ha->fw_image->size > 4096)) {
- ret = FAIL_FILE_SIZE;
- goto out;
}
payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
@@ -544,6 +548,10 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
payload->minor_function = 0x1;
pm8001_ha->nvmd_completion = &completion;
ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);
+ if (ret) {
+ pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+ goto out;
+ }
wait_for_completion(&completion);
out:
kfree(ioctlbuffer);
@@ -554,35 +562,31 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
{
struct pm8001_ioctl_payload *payload;
DECLARE_COMPLETION_ONSTACK(completion);
- u8 *ioctlbuffer = NULL;
- u32 length = 0;
+ u8 *ioctlbuffer;
struct fw_control_info *fwControl;
- u32 loopNumber, loopcount = 0;
- u32 sizeRead = 0;
u32 partitionSize, partitionSizeTmp;
- u32 ret = 0;
- u32 partitionNumber = 0;
+ u32 loopNumber, loopcount;
struct pm8001_fw_image_header *image_hdr;
+ u32 sizeRead = 0;
+ u32 ret = 0;
+ u32 length = 1024 * 16 + sizeof(*payload) - 1;
- length = 1024 * 16 + sizeof(*payload) - 1;
+ if (pm8001_ha->fw_image->size < 28) {
+ pm8001_ha->fw_status = FAIL_FILE_SIZE;
+ return -EFAULT;
+ }
ioctlbuffer = kzalloc(length, GFP_KERNEL);
- image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
- if (!ioctlbuffer)
+ if (!ioctlbuffer) {
+ pm8001_ha->fw_status = FAIL_OUT_MEMORY;
return -ENOMEM;
- if (pm8001_ha->fw_image->size < 28) {
- ret = FAIL_FILE_SIZE;
- goto out;
}
-
+ image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
while (sizeRead < pm8001_ha->fw_image->size) {
partitionSizeTmp =
*(u32 *)((u8 *)&image_hdr->image_length + sizeRead);
partitionSize = be32_to_cpu(partitionSizeTmp);
- loopcount = (partitionSize + HEADER_LEN)/IOCTL_BUF_SIZE;
- if (loopcount % IOCTL_BUF_SIZE)
- loopcount++;
- if (loopcount == 0)
- loopcount++;
+ loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN,
+ IOCTL_BUF_SIZE);
for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
payload->length = 1024*16;
@@ -614,18 +618,18 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->nvmd_completion = &completion;
ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);
+ if (ret) {
+ pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+ goto out;
+ }
wait_for_completion(&completion);
- if (ret || (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS)) {
- ret = fwControl->retcode;
- kfree(ioctlbuffer);
- ioctlbuffer = NULL;
- break;
+ if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) {
+ pm8001_ha->fw_status = fwControl->retcode;
+ ret = -EFAULT;
+ goto out;
+ }
}
}
- if (ret)
- break;
- partitionNumber++;
-}
out:
kfree(ioctlbuffer);
return ret;
@@ -640,22 +644,29 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,
char *cmd_ptr, *filename_ptr;
int res, i;
int flash_command = FLASH_CMD_NONE;
- int err = 0;
+ int ret;
+
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+ /* this test protects us from running two flash processes at once,
+ * so we should start with this test */
+ if (pm8001_ha->fw_status == FLASH_IN_PROGRESS)
+ return -EINPROGRESS;
+ pm8001_ha->fw_status = FLASH_IN_PROGRESS;
+ cmd_ptr = kzalloc(count*2, GFP_KERNEL);
if (!cmd_ptr) {
- err = FAIL_OUT_MEMORY;
- goto out;
+ pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+ return -ENOMEM;
}
filename_ptr = cmd_ptr + count;
res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
if (res != 2) {
- err = FAIL_PARAMETERS;
- goto out1;
+ pm8001_ha->fw_status = FAIL_PARAMETERS;
+ ret = -EINVAL;
+ goto out;
}
for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
@@ -666,50 +677,38 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,
}
}
if (flash_command == FLASH_CMD_NONE) {
- err = FAIL_PARAMETERS;
- goto out1;
+ pm8001_ha->fw_status = FAIL_PARAMETERS;
+ ret = -EINVAL;
+ goto out;
}
- if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) {
- err = FLASH_IN_PROGRESS;
- goto out1;
- }
- err = request_firmware(&pm8001_ha->fw_image,
+ ret = request_firmware(&pm8001_ha->fw_image,
filename_ptr,
pm8001_ha->dev);
- if (err) {
+ if (ret) {
PM8001_FAIL_DBG(pm8001_ha,
- pm8001_printk("Failed to load firmware image file %s,"
- " error %d\n", filename_ptr, err));
- err = FAIL_OPEN_BIOS_FILE;
- goto out1;
+ pm8001_printk(
+ "Failed to load firmware image file %s, error %d\n",
+ filename_ptr, ret));
+ pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE;
+ goto out;
}
- switch (flash_command) {
- case FLASH_CMD_UPDATE:
- pm8001_ha->fw_status = FLASH_IN_PROGRESS;
- err = pm8001_update_flash(pm8001_ha);
- break;
- case FLASH_CMD_SET_NVMD:
- pm8001_ha->fw_status = FLASH_IN_PROGRESS;
- err = pm8001_set_nvmd(pm8001_ha);
- break;
- default:
- pm8001_ha->fw_status = FAIL_PARAMETERS;
- err = FAIL_PARAMETERS;
- break;
- }
+ if (FLASH_CMD_UPDATE == flash_command)
+ ret = pm8001_update_flash(pm8001_ha);
+ else
+ ret = pm8001_set_nvmd(pm8001_ha);
+
release_firmware(pm8001_ha->fw_image);
-out1:
- kfree(cmd_ptr);
out:
- pm8001_ha->fw_status = err;
+ kfree(cmd_ptr);
- if (!err)
- return count;
- else
- return -err;
+ if (ret)
+ return ret;
+
+ pm8001_ha->fw_status = FLASH_OK;
+ return count;
}
static ssize_t pm8001_show_update_fw(struct device *cdev,
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index a97be015e52e..dd12c6fe57a6 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1346,7 +1346,7 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
&pMessage) < 0) {
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("No free mpi buffer\n"));
- return -1;
+ return -ENOMEM;
}
BUG_ON(!payload);
/*Copy to the payload*/
@@ -1751,6 +1751,8 @@ static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha,
task_abort.tag = cpu_to_le32(ccb_tag);
ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0);
+ if (ret)
+ pm8001_tag_free(pm8001_ha, ccb_tag);
}
@@ -1778,6 +1780,7 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha,
res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
if (res) {
+ sas_free_task(task);
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("cannot allocate tag !!!\n"));
return;
@@ -1788,14 +1791,14 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha,
*/
dev = kzalloc(sizeof(struct domain_device), GFP_ATOMIC);
if (!dev) {
+ sas_free_task(task);
+ pm8001_tag_free(pm8001_ha, ccb_tag);
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("Domain device cannot be allocated\n"));
- sas_free_task(task);
return;
- } else {
- task->dev = dev;
- task->dev->lldd_dev = pm8001_ha_dev;
}
+ task->dev = dev;
+ task->dev->lldd_dev = pm8001_ha_dev;
ccb = &pm8001_ha->ccb_info[ccb_tag];
ccb->device = pm8001_ha_dev;
@@ -1821,7 +1824,11 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha,
memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis));
res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0);
-
+ if (res) {
+ sas_free_task(task);
+ pm8001_tag_free(pm8001_ha, ccb_tag);
+ kfree(dev);
+ }
}
/**
@@ -3100,7 +3107,7 @@ void pm8001_mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha,
complete(pm8001_dev->setds_completion);
ccb->task = NULL;
ccb->ccb_tag = 0xFFFFFFFF;
- pm8001_ccb_free(pm8001_ha, tag);
+ pm8001_tag_free(pm8001_ha, tag);
}
void pm8001_mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
@@ -3119,13 +3126,12 @@ void pm8001_mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
}
ccb->task = NULL;
ccb->ccb_tag = 0xFFFFFFFF;
- pm8001_ccb_free(pm8001_ha, tag);
+ pm8001_tag_free(pm8001_ha, tag);
}
void
pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
- struct fw_control_ex *fw_control_context;
struct get_nvm_data_resp *pPayload =
(struct get_nvm_data_resp *)(piomb + 4);
u32 tag = le32_to_cpu(pPayload->tag);
@@ -3134,7 +3140,6 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
u32 ir_tds_bn_dps_das_nvm =
le32_to_cpu(pPayload->ir_tda_bn_dps_das_nvm);
void *virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr;
- fw_control_context = ccb->fw_control_context;
PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Get nvm data complete!\n"));
if ((dlen_status & NVMD_STAT) != 0) {
@@ -3175,13 +3180,11 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
pm8001_printk("Get NVMD success, IR=0, dataLen=%d\n",
(dlen_status & NVMD_LEN) >> 24));
}
- memcpy(fw_control_context->usrAddr,
- pm8001_ha->memoryMap.region[NVMD].virt_ptr,
- fw_control_context->len);
- complete(pm8001_ha->nvmd_completion);
+ kfree(ccb->fw_control_context);
ccb->task = NULL;
ccb->ccb_tag = 0xFFFFFFFF;
- pm8001_ccb_free(pm8001_ha, tag);
+ pm8001_tag_free(pm8001_ha, tag);
+ complete(pm8001_ha->nvmd_completion);
}
int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb)
@@ -3588,7 +3591,7 @@ int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
complete(pm8001_dev->dcompletion);
ccb->task = NULL;
ccb->ccb_tag = 0xFFFFFFFF;
- pm8001_ccb_free(pm8001_ha, htag);
+ pm8001_tag_free(pm8001_ha, htag);
return 0;
}
@@ -3617,15 +3620,11 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
u32 status;
- struct fw_control_ex fw_control_context;
struct fw_flash_Update_resp *ppayload =
(struct fw_flash_Update_resp *)(piomb + 4);
u32 tag = le32_to_cpu(ppayload->tag);
struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
status = le32_to_cpu(ppayload->status);
- memcpy(&fw_control_context,
- ccb->fw_control_context,
- sizeof(fw_control_context));
switch (status) {
case FLASH_UPDATE_COMPLETE_PENDING_REBOOT:
PM8001_MSG_DBG(pm8001_ha,
@@ -3668,11 +3667,11 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
pm8001_printk("No matched status = %d\n", status));
break;
}
- ccb->fw_control_context->fw_control->retcode = status;
- complete(pm8001_ha->nvmd_completion);
+ kfree(ccb->fw_control_context);
ccb->task = NULL;
ccb->ccb_tag = 0xFFFFFFFF;
- pm8001_ccb_free(pm8001_ha, tag);
+ pm8001_tag_free(pm8001_ha, tag);
+ complete(pm8001_ha->nvmd_completion);
return 0;
}
@@ -4257,7 +4256,11 @@ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
smp_cmd.long_smp_req.long_resp_size =
cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd);
- pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, (u32 *)&smp_cmd, 0);
+ rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
+ (u32 *)&smp_cmd, 0);
+ if (rc)
+ goto err_out_2;
+
return 0;
err_out_2:
@@ -4398,7 +4401,7 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
/* Check for read log for failed drive and return */
if (sata_cmd.sata_fis.command == 0x2f) {
- if (pm8001_ha_dev && ((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) ||
+ if (((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) ||
(pm8001_ha_dev->id & NCQ_ABORT_ALL_FLAG) ||
(pm8001_ha_dev->id & NCQ_2ND_RLE_FLAG))) {
struct task_status_struct *ts;
@@ -4789,6 +4792,10 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
break;
}
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, 0);
+ if (rc) {
+ kfree(fw_control_context);
+ pm8001_tag_free(pm8001_ha, tag);
+ }
return rc;
}
@@ -4817,7 +4824,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc) {
kfree(fw_control_context);
- return rc;
+ return -EBUSY;
}
ccb = &pm8001_ha->ccb_info[tag];
ccb->fw_control_context = fw_control_context;
@@ -4869,6 +4876,10 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
break;
}
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, 0);
+ if (rc) {
+ kfree(fw_control_context);
+ pm8001_tag_free(pm8001_ha, tag);
+ }
return rc;
}
@@ -4935,7 +4946,7 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc) {
kfree(fw_control_context);
- return rc;
+ return -EBUSY;
}
ccb = &pm8001_ha->ccb_info[tag];
ccb->fw_control_context = fw_control_context;
@@ -5061,7 +5072,7 @@ pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
memset(&payload, 0, sizeof(payload));
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc)
- return -1;
+ return -ENOMEM;
ccb = &pm8001_ha->ccb_info[tag];
ccb->ccb_tag = tag;
circularQ = &pm8001_ha->inbnd_q_tbl[0];
@@ -5070,6 +5081,8 @@ pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
payload.sata_hol_tmo = cpu_to_le32(80);
payload.open_reject_cmdretries_data_retries = cpu_to_le32(0xff00ff);
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
return rc;
}
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index e90c89f1d480..666bf5af06e2 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -246,6 +246,7 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
{
int i;
spin_lock_init(&pm8001_ha->lock);
+ spin_lock_init(&pm8001_ha->bitmap_lock);
PM8001_INIT_DBG(pm8001_ha,
pm8001_printk("pm8001_alloc: PHY:%x\n",
pm8001_ha->chip->n_phy));
@@ -621,6 +622,8 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
DECLARE_COMPLETION_ONSTACK(completion);
struct pm8001_ioctl_payload payload;
u16 deviceid;
+ int rc;
+
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
pm8001_ha->nvmd_completion = &completion;
@@ -638,7 +641,16 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
}
payload.offset = 0;
payload.func_specific = kzalloc(payload.length, GFP_KERNEL);
- PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
+ if (!payload.func_specific) {
+ PM8001_INIT_DBG(pm8001_ha, pm8001_printk("mem alloc fail\n"));
+ return;
+ }
+ rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
+ if (rc) {
+ kfree(payload.func_specific);
+ PM8001_INIT_DBG(pm8001_ha, pm8001_printk("nvmd failed\n"));
+ return;
+ }
wait_for_completion(&completion);
for (i = 0, j = 0; i <= 7; i++, j++) {
@@ -661,6 +673,7 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
pm8001_printk("phy %d sas_addr = %016llx\n", i,
pm8001_ha->phy[i].dev_sas_addr));
}
+ kfree(payload.func_specific);
#else
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
pm8001_ha->phy[i].dev_sas_addr = 0x50010c600047f9d0ULL;
@@ -684,6 +697,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
/*OPTION ROM FLASH read for the SPC cards */
DECLARE_COMPLETION_ONSTACK(completion);
struct pm8001_ioctl_payload payload;
+ int rc;
pm8001_ha->nvmd_completion = &completion;
/* SAS ADDRESS read from flash / EEPROM */
@@ -694,7 +708,12 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
if (!payload.func_specific)
return -ENOMEM;
/* Read phy setting values from flash */
- PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
+ rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
+ if (rc) {
+ kfree(payload.func_specific);
+ PM8001_INIT_DBG(pm8001_ha, pm8001_printk("nvmd failed\n"));
+ return -ENOMEM;
+ }
wait_for_completion(&completion);
pm8001_set_phy_profile(pm8001_ha, sizeof(u8), payload.func_specific);
kfree(payload.func_specific);
@@ -729,33 +748,35 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
sizeof(pm8001_ha->msix_entries[0]);
for (i = 0; i < max_entry ; i++)
pm8001_ha->msix_entries[i].entry = i;
- rc = pci_enable_msix(pm8001_ha->pdev, pm8001_ha->msix_entries,
+ rc = pci_enable_msix_exact(pm8001_ha->pdev, pm8001_ha->msix_entries,
number_of_intr);
pm8001_ha->number_of_intr = number_of_intr;
- if (!rc) {
- PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
- "pci_enable_msix request ret:%d no of intr %d\n",
- rc, pm8001_ha->number_of_intr));
-
-
- for (i = 0; i < number_of_intr; i++) {
- snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
- DRV_NAME"%d", i);
- pm8001_ha->irq_vector[i].irq_id = i;
- pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
-
- if (request_irq(pm8001_ha->msix_entries[i].vector,
- pm8001_interrupt_handler_msix, flag,
- intr_drvname[i], &(pm8001_ha->irq_vector[i]))) {
- for (j = 0; j < i; j++)
- free_irq(
- pm8001_ha->msix_entries[j].vector,
+ if (rc)
+ return rc;
+
+ PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
+ "pci_enable_msix_exact request ret:%d no of intr %d\n",
+ rc, pm8001_ha->number_of_intr));
+
+ for (i = 0; i < number_of_intr; i++) {
+ snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
+ DRV_NAME"%d", i);
+ pm8001_ha->irq_vector[i].irq_id = i;
+ pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
+
+ rc = request_irq(pm8001_ha->msix_entries[i].vector,
+ pm8001_interrupt_handler_msix, flag,
+ intr_drvname[i], &(pm8001_ha->irq_vector[i]));
+ if (rc) {
+ for (j = 0; j < i; j++) {
+ free_irq(pm8001_ha->msix_entries[j].vector,
&(pm8001_ha->irq_vector[i]));
- pci_disable_msix(pm8001_ha->pdev);
- break;
}
+ pci_disable_msix(pm8001_ha->pdev);
+ break;
}
}
+
return rc;
}
#endif
@@ -964,6 +985,7 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
int i, j;
u32 device_state;
pm8001_ha = sha->lldd_ha;
+ sas_suspend_ha(sha);
flush_workqueue(pm8001_wq);
scsi_block_requests(pm8001_ha->shost);
if (!pdev->pm_cap) {
@@ -1013,6 +1035,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
int rc;
u8 i = 0, j;
u32 device_state;
+ DECLARE_COMPLETION_ONSTACK(completion);
pm8001_ha = sha->lldd_ha;
device_state = pdev->current_state;
@@ -1033,7 +1056,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
rc = pci_go_44(pdev);
if (rc)
goto err_out_disable;
-
+ sas_prep_resume_ha(sha);
/* chip soft rst only for spc */
if (pm8001_ha->chip_id == chip_8001) {
PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
@@ -1065,7 +1088,13 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
for (i = 1; i < pm8001_ha->number_of_intr; i++)
PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i);
}
- scsi_unblock_requests(pm8001_ha->shost);
+ pm8001_ha->flags = PM8001F_RUN_TIME;
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+ pm8001_ha->phy[i].enable_completion = &completion;
+ PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i);
+ wait_for_completion(&completion);
+ }
+ sas_resume_ha(sha);
return 0;
err_out_disable:
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 8a44bc92bc78..76570e6a547d 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -58,25 +58,14 @@ static int pm8001_find_tag(struct sas_task *task, u32 *tag)
}
/**
- * pm8001_tag_clear - clear the tags bitmap
+ * pm8001_tag_free - free the no more needed tag
* @pm8001_ha: our hba struct
* @tag: the found tag associated with the task
*/
-static void pm8001_tag_clear(struct pm8001_hba_info *pm8001_ha, u32 tag)
-{
- void *bitmap = pm8001_ha->tags;
- clear_bit(tag, bitmap);
-}
-
void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag)
{
- pm8001_tag_clear(pm8001_ha, tag);
-}
-
-static void pm8001_tag_set(struct pm8001_hba_info *pm8001_ha, u32 tag)
-{
void *bitmap = pm8001_ha->tags;
- set_bit(tag, bitmap);
+ clear_bit(tag, bitmap);
}
/**
@@ -86,14 +75,18 @@ static void pm8001_tag_set(struct pm8001_hba_info *pm8001_ha, u32 tag)
*/
inline int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out)
{
- unsigned int index, tag;
+ unsigned int tag;
void *bitmap = pm8001_ha->tags;
+ unsigned long flags;
- index = find_first_zero_bit(bitmap, pm8001_ha->tags_num);
- tag = index;
- if (tag >= pm8001_ha->tags_num)
+ spin_lock_irqsave(&pm8001_ha->bitmap_lock, flags);
+ tag = find_first_zero_bit(bitmap, pm8001_ha->tags_num);
+ if (tag >= pm8001_ha->tags_num) {
+ spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags);
return -SAS_QUEUE_FULL;
- pm8001_tag_set(pm8001_ha, tag);
+ }
+ set_bit(tag, bitmap);
+ spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags);
*tag_out = tag;
return 0;
}
@@ -102,7 +95,7 @@ void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha)
{
int i;
for (i = 0; i < pm8001_ha->tags_num; ++i)
- pm8001_tag_clear(pm8001_ha, i);
+ pm8001_tag_free(pm8001_ha, i);
}
/**
@@ -123,13 +116,12 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
u64 align_offset = 0;
if (align)
align_offset = (dma_addr_t)align - 1;
- mem_virt_alloc =
- pci_alloc_consistent(pdev, mem_size + align, &mem_dma_handle);
+ mem_virt_alloc = pci_zalloc_consistent(pdev, mem_size + align,
+ &mem_dma_handle);
if (!mem_virt_alloc) {
pm8001_printk("memory allocation error\n");
return -1;
}
- memset((void *)mem_virt_alloc, 0, mem_size+align);
*pphys_addr = mem_dma_handle;
phys_align = (*pphys_addr + align_offset) & ~align_offset;
*virt_addr = (void *)mem_virt_alloc + phys_align - *pphys_addr;
@@ -501,11 +493,6 @@ int pm8001_queue_command(struct sas_task *task, const int num,
return pm8001_task_exec(task, num, gfp_flags, 0, NULL);
}
-void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx)
-{
- pm8001_tag_clear(pm8001_ha, ccb_idx);
-}
-
/**
* pm8001_ccb_task_free - free the sg for ssp and smp command, free the ccb.
* @pm8001_ha: our hba card information
@@ -542,7 +529,7 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
ccb->task = NULL;
ccb->ccb_tag = 0xFFFFFFFF;
ccb->open_retry = 0;
- pm8001_ccb_free(pm8001_ha, ccb_idx);
+ pm8001_tag_free(pm8001_ha, ccb_idx);
}
/**
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 1ee06f21803b..f6b2ac59dae4 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -475,6 +475,7 @@ struct pm8001_hba_info {
struct list_head list;
unsigned long flags;
spinlock_t lock;/* host-wide lock */
+ spinlock_t bitmap_lock;
struct pci_dev *pdev;/* our device */
struct device *dev;
struct pm8001_hba_memspace io_mem[6];
@@ -616,7 +617,6 @@ extern struct workqueue_struct *pm8001_wq;
int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out);
void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha);
u32 pm8001_get_ncq_tag(struct sas_task *task, u32 *tag);
-void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx);
void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx);
int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index d70587f96184..b06443a0db2d 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -856,6 +856,8 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha)
payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8);
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
return rc;
}
@@ -936,6 +938,8 @@ pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha)
sizeof(SASProtocolTimerConfig_t));
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
return rc;
}
@@ -948,7 +952,7 @@ static int
pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha)
{
u32 scratch3_value;
- int ret;
+ int ret = -1;
/* Read encryption status from SCRATCH PAD 3 */
scratch3_value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
@@ -982,7 +986,7 @@ pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->encrypt_info.status = 0xFFFFFFFF;
pm8001_ha->encrypt_info.cipher_mode = 0;
pm8001_ha->encrypt_info.sec_mode = 0;
- return 0;
+ ret = 0;
} else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) ==
SCRATCH_PAD3_ENC_DIS_ERR) {
pm8001_ha->encrypt_info.status =
@@ -1004,7 +1008,6 @@ pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha)
scratch3_value, pm8001_ha->encrypt_info.cipher_mode,
pm8001_ha->encrypt_info.sec_mode,
pm8001_ha->encrypt_info.status));
- ret = -1;
} else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) ==
SCRATCH_PAD3_ENC_ENA_ERR) {
@@ -1028,7 +1031,6 @@ pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha)
scratch3_value, pm8001_ha->encrypt_info.cipher_mode,
pm8001_ha->encrypt_info.sec_mode,
pm8001_ha->encrypt_info.status));
- ret = -1;
}
return ret;
}
@@ -1059,6 +1061,8 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha)
KEK_MGMT_SUBOP_KEYCARDUPDATE);
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
return rc;
}
@@ -1383,8 +1387,10 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha,
task->task_done = pm8001_task_done;
res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
- if (res)
+ if (res) {
+ sas_free_task(task);
return;
+ }
ccb = &pm8001_ha->ccb_info[ccb_tag];
ccb->device = pm8001_ha_dev;
@@ -1399,7 +1405,10 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha,
task_abort.tag = cpu_to_le32(ccb_tag);
ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0);
-
+ if (ret) {
+ sas_free_task(task);
+ pm8001_tag_free(pm8001_ha, ccb_tag);
+ }
}
static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha,
@@ -1426,6 +1435,7 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha,
res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
if (res) {
+ sas_free_task(task);
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("cannot allocate tag !!!\n"));
return;
@@ -1436,15 +1446,16 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha,
*/
dev = kzalloc(sizeof(struct domain_device), GFP_ATOMIC);
if (!dev) {
+ sas_free_task(task);
+ pm8001_tag_free(pm8001_ha, ccb_tag);
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("Domain device cannot be allocated\n"));
- sas_free_task(task);
return;
- } else {
- task->dev = dev;
- task->dev->lldd_dev = pm8001_ha_dev;
}
+ task->dev = dev;
+ task->dev->lldd_dev = pm8001_ha_dev;
+
ccb = &pm8001_ha->ccb_info[ccb_tag];
ccb->device = pm8001_ha_dev;
ccb->ccb_tag = ccb_tag;
@@ -1469,7 +1480,11 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha,
memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis));
res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0);
-
+ if (res) {
+ sas_free_task(task);
+ pm8001_tag_free(pm8001_ha, ccb_tag);
+ kfree(dev);
+ }
}
/**
@@ -3815,7 +3830,10 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag,
&smp_cmd, pm8001_ha->smp_exp_mode, length);
- pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, (u32 *)&smp_cmd, 0);
+ rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
+ (u32 *)&smp_cmd, 0);
+ if (rc)
+ goto err_out_2;
return 0;
err_out_2:
@@ -4406,6 +4424,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
SAS_ADDR_SIZE);
rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
return rc;
}
@@ -4484,7 +4504,9 @@ void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
payload.reserved[j] = cpu_to_le32(*((u32 *)buf + i));
j++;
}
- pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
}
void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,