Re: [PATCH 2/2] qla1280: retain firmware for error recovery

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi James,

I've seen no response from Jes on this patch.  I'm uncertain how to reach
him these days.  Have you any comments on this patch?

Thanks,
 Mike


Michael Reed wrote:
> The qla1280 driver acquires its firmware via udev.  During boot the firmware
> is located in the initrd.  If, after root is mounted, the adapter needs to
> reload firmware (host reset), the firmware load may fail if the root device
> is on the adapter being reset.  This patch modifies qla1280 to retain the
> firmware loaded via the initial request_firmware() for use during error
> recovery.
> 
> Signed-off-by: Michael Reed <mdr@xxxxxxx>
> 
> 
> --- linux-2.6.32.5-0.1/drivers/scsi/qla1280.c	2010-02-04 16:23:10.831352910 -0600
> +++ linux-2.6.32.5-0.1-modified/drivers/scsi/qla1280.c	2010-02-08 15:05:42.402094235 -0600
> @@ -17,9 +17,11 @@
>  * General Public License for more details.
>  *
>  ******************************************************************************/
> -#define QLA1280_VERSION      "3.27"
> +#define QLA1280_VERSION      "3.27.1"
>  /*****************************************************************************
>      Revision History:
> +    Rev  3.27.1, February 8, 2010, Michael Reed
> +	- Retain firmware image for error recovery.
>      Rev  3.27, February 10, 2009, Michael Reed
>  	- General code cleanup.
>  	- Improve error recovery.
> @@ -538,9 +540,9 @@ __setup("qla1280=", qla1280_setup);
>  /*****************************************/
>  
>  struct qla_boards {
> -	unsigned char name[9];	/* Board ID String */
> +	char *name;		/* Board ID String */
>  	int numPorts;		/* Number of SCSI ports */
> -	char *fwname;		/* firmware name        */
> +	int fw_index;		/* index into qla1280_fw_tbl for firmware */
>  };
>  
>  /* NOTE: the last argument in each entry is used to index ql1280_board_tbl */
> @@ -561,15 +563,30 @@ static struct pci_device_id qla1280_pci_
>  };
>  MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl);
>  
> +DEFINE_MUTEX(qla1280_firmware_mutex);
> +
> +struct qla_fw {
> +	char *fwname;
> +	const struct firmware *fw;
> +};
> +
> +#define QL_NUM_FW_IMAGES 3
> +
> +struct qla_fw qla1280_fw_tbl[QL_NUM_FW_IMAGES] = {
> +	{"qlogic/1040.bin",  NULL},	/* image 0 */
> +	{"qlogic/1280.bin",  NULL},	/* image 1 */
> +	{"qlogic/12160.bin", NULL},	/* image 2 */
> +};
> +
> +/* NOTE: Order of boards in this table must match order in qla1280_pci_tbl */
>  static struct qla_boards ql1280_board_tbl[] = {
> -	/* Name ,  Number of ports, FW details */
> -	{"QLA12160",	2, "qlogic/12160.bin"},
> -	{"QLA1040",	1, "qlogic/1040.bin"},
> -	{"QLA1080",	1, "qlogic/1280.bin"},
> -	{"QLA1240",	2, "qlogic/1280.bin"},
> -	{"QLA1280",	2, "qlogic/1280.bin"},
> -	{"QLA10160",	1, "qlogic/12160.bin"},
> -	{"        ",	0, "   "},
> +	{.name="QLA12160", .numPorts=2, .fw_index=2},
> +	{.name="QLA1040" , .numPorts=1, .fw_index=0},
> +	{.name="QLA1080" , .numPorts=1, .fw_index=1},
> +	{.name="QLA1240" , .numPorts=2, .fw_index=1},
> +	{.name="QLA1280" , .numPorts=2, .fw_index=1},
> +	{.name="QLA10160", .numPorts=1, .fw_index=2},
> +	{.name="        ", .numPorts=0, .fw_index=-1},
>  };
>  
>  static int qla1280_verbose = 1;
> @@ -1512,6 +1529,63 @@ qla1280_initialize_adapter(struct scsi_q
>  }
>  
>  /*
> + * qla1280_request_firmware
> + *      Acquire firmware for chip.  Retain in memory
> + *      for error recovery.
> + *
> + * Input:
> + *      ha = adapter block pointer.
> + *
> + * Returns:
> + *      Pointer to firmware image or an error code
> + *      cast to pointer via ERR_PTR().
> + */
> +static const struct firmware *
> +qla1280_request_firmware(struct scsi_qla_host *ha)
> +{
> +	const struct firmware *fw;
> +	int err;
> +	int index;
> +	char *fwname;
> +
> +	spin_unlock_irq(ha->host->host_lock);
> +	mutex_lock(&qla1280_firmware_mutex);
> +
> +	index = ql1280_board_tbl[ha->devnum].fw_index;
> +	fw = qla1280_fw_tbl[index].fw;
> +	if (fw)
> +		goto out;
> +
> +	fwname = qla1280_fw_tbl[index].fwname;
> +	err = request_firmware(&fw, fwname, &ha->pdev->dev);
> +	
> +	if (err) {
> +		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
> +		       fwname, err);
> +		fw = ERR_PTR(err);
> +		goto unlock;
> +	}
> +	if ((fw->size % 2) || (fw->size < 6)) {
> +		printk(KERN_ERR "Invalid firmware length %zu in image \"%s\"\n",
> +		       fw->size, fwname);
> +		release_firmware(fw);
> +		fw = ERR_PTR(-EINVAL);
> +		goto unlock;
> +	}
> +
> +	qla1280_fw_tbl[index].fw = fw;
> +
> + out:
> +	ha->fwver1 = fw->data[0];
> +	ha->fwver2 = fw->data[1];
> +	ha->fwver3 = fw->data[2];
> + unlock:
> +	mutex_unlock(&qla1280_firmware_mutex);
> +	spin_lock_irq(ha->host->host_lock);
> +	return fw;
> +}
> +
> +/*
>   * Chip diagnostics
>   *      Test chip for proper operation.
>   *
> @@ -1634,30 +1708,18 @@ qla1280_chip_diag(struct scsi_qla_host *
>  static int
>  qla1280_load_firmware_pio(struct scsi_qla_host *ha)
>  {
> +	/* enter with host_lock acquired */
> +
>  	const struct firmware *fw;
>  	const __le16 *fw_data;
>  	uint16_t risc_address, risc_code_size;
>  	uint16_t mb[MAILBOX_REGISTER_COUNT], i;
> -	int err;
> +	int err=0;
> +
> +	fw = qla1280_request_firmware(ha);
> +	if (IS_ERR(fw))
> +		return PTR_ERR(fw);
>  
> -	spin_unlock_irq(ha->host->host_lock);
> -	err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname,
> -			       &ha->pdev->dev);
> -	spin_lock_irq(ha->host->host_lock);
> -	if (err) {
> -		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
> -		       ql1280_board_tbl[ha->devnum].fwname, err);
> -		return err;
> -	}
> -	if ((fw->size % 2) || (fw->size < 6)) {
> -		printk(KERN_ERR "Bogus length %zu in image \"%s\"\n",
> -		       fw->size, ql1280_board_tbl[ha->devnum].fwname);
> -		err = -EINVAL;
> -		goto out;
> -	}
> -	ha->fwver1 = fw->data[0];
> -	ha->fwver2 = fw->data[1];
> -	ha->fwver3 = fw->data[2];
>  	fw_data = (const __le16 *)&fw->data[0];
>  	ha->fwstart = __le16_to_cpu(fw_data[2]);
>  
> @@ -1675,11 +1737,10 @@ qla1280_load_firmware_pio(struct scsi_ql
>  		if (err) {
>  			printk(KERN_ERR "scsi(%li): Failed to load firmware\n",
>  					ha->host_no);
> -			goto out;
> +			break;
>  		}
>  	}
> -out:
> -	release_firmware(fw);
> +
>  	return err;
>  }
>  
> @@ -1687,6 +1748,7 @@ out:
>  static int
>  qla1280_load_firmware_dma(struct scsi_qla_host *ha)
>  {
> +	/* enter with host_lock acquired */
>  	const struct firmware *fw;
>  	const __le16 *fw_data;
>  	uint16_t risc_address, risc_code_size;
> @@ -1701,24 +1763,10 @@ qla1280_load_firmware_dma(struct scsi_ql
>  		return -ENOMEM;
>  #endif
>  
> -	spin_unlock_irq(ha->host->host_lock);
> -	err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname,
> -			       &ha->pdev->dev);
> -	spin_lock_irq(ha->host->host_lock);
> -	if (err) {
> -		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
> -		       ql1280_board_tbl[ha->devnum].fwname, err);
> -		return err;
> -	}
> -	if ((fw->size % 2) || (fw->size < 6)) {
> -		printk(KERN_ERR "Bogus length %zu in image \"%s\"\n",
> -		       fw->size, ql1280_board_tbl[ha->devnum].fwname);
> -		err = -EINVAL;
> -		goto out;
> -	}
> -	ha->fwver1 = fw->data[0];
> -	ha->fwver2 = fw->data[1];
> -	ha->fwver3 = fw->data[2];
> +	fw = qla1280_request_firmware(ha);
> +	if (IS_ERR(fw))
> +		return PTR_ERR(fw);
> +
>  	fw_data = (const __le16 *)&fw->data[0];
>  	ha->fwstart = __le16_to_cpu(fw_data[2]);
>  
> @@ -1803,7 +1851,6 @@ qla1280_load_firmware_dma(struct scsi_ql
>  #if DUMP_IT_BACK
>  	pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf);
>  #endif
> -	release_firmware(fw);
>  	return err;
>  }
>  
> @@ -1842,6 +1889,7 @@ qla1280_start_firmware(struct scsi_qla_h
>  static int
>  qla1280_load_firmware(struct scsi_qla_host *ha)
>  {
> +	/* enter with host_lock taken */
>  	int err;
>  
>  	err = qla1280_chip_diag(ha);
> @@ -4420,7 +4468,16 @@ qla1280_init(void)
>  static void __exit
>  qla1280_exit(void)
>  {
> +	int i;
> +
>  	pci_unregister_driver(&qla1280_pci_driver);
> +	/* release any allocated firmware images */
> +	for (i=0; i<QL_NUM_FW_IMAGES; i++) {
> +		if (qla1280_fw_tbl[i].fw) {
> +			release_firmware(qla1280_fw_tbl[i].fw);
> +			qla1280_fw_tbl[i].fw = NULL;
> +		}
> +	}
>  }
>  
>  module_init(qla1280_init);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux