diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 377 | 
1 files changed, 226 insertions, 151 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 9598fdcb08a..411ed48d79d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -64,8 +64,8 @@ static int lpfc_sli4_queue_verify(struct lpfc_hba *);  static int lpfc_create_bootstrap_mbox(struct lpfc_hba *);  static int lpfc_setup_endian_order(struct lpfc_hba *);  static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); -static void lpfc_free_sgl_list(struct lpfc_hba *); -static int lpfc_init_sgl_list(struct lpfc_hba *); +static void lpfc_free_els_sgl_list(struct lpfc_hba *); +static void lpfc_init_sgl_list(struct lpfc_hba *);  static int lpfc_init_active_sgl_array(struct lpfc_hba *);  static void lpfc_free_active_sgl(struct lpfc_hba *);  static int lpfc_hba_down_post_s3(struct lpfc_hba *phba); @@ -2767,47 +2767,14 @@ lpfc_offline(struct lpfc_hba *phba)  }  /** - * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated. - * @phba: pointer to lpfc hba data structure. - * - * This routine goes through all the scsi buffers in the system and updates the - * Physical XRIs assigned to the SCSI buffer because these may change after any - * firmware reset - * - * Return codes - *   0 - successful (for now, it always returns 0) - **/ -int -lpfc_scsi_buf_update(struct lpfc_hba *phba) -{ -	struct lpfc_scsi_buf *sb, *sb_next; - -	spin_lock_irq(&phba->hbalock); -	spin_lock(&phba->scsi_buf_list_lock); -	list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { -		sb->cur_iocbq.sli4_xritag = -			phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; -		set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask); -		phba->sli4_hba.max_cfg_param.xri_used++; -		phba->sli4_hba.xri_count++; -	} -	spin_unlock(&phba->scsi_buf_list_lock); -	spin_unlock_irq(&phba->hbalock); -	return 0; -} - -/**   * lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists   * @phba: pointer to lpfc hba data structure.   *   * This routine is to free all the SCSI buffers and IOCBs from the driver   * list back to kernel. It is called from lpfc_pci_remove_one to free   * the internal resources before the device is removed from the system. - * - * Return codes - *   0 - successful (for now, it always returns 0)   **/ -static int +static void  lpfc_scsi_free(struct lpfc_hba *phba)  {  	struct lpfc_scsi_buf *sb, *sb_next; @@ -2833,7 +2800,178 @@ lpfc_scsi_free(struct lpfc_hba *phba)  	}  	spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_xri_sgl_update - update xri-sgl sizing and mapping + * @phba: pointer to lpfc hba data structure. + * + * This routine first calculates the sizes of the current els and allocated + * scsi sgl lists, and then goes through all sgls to updates the physical + * XRIs assigned due to port function reset. During port initialization, the + * current els and allocated scsi sgl lists are 0s. + * + * Return codes + *   0 - successful (for now, it always returns 0) + **/ +int +lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba) +{ +	struct lpfc_sglq *sglq_entry = NULL, *sglq_entry_next = NULL; +	struct lpfc_scsi_buf *psb = NULL, *psb_next = NULL; +	uint16_t i, lxri, xri_cnt, els_xri_cnt, scsi_xri_cnt; +	LIST_HEAD(els_sgl_list); +	LIST_HEAD(scsi_sgl_list); +	int rc; + +	/* +	 * update on pci function's els xri-sgl list +	 */ +	els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); +	if (els_xri_cnt > phba->sli4_hba.els_xri_cnt) { +		/* els xri-sgl expanded */ +		xri_cnt = els_xri_cnt - phba->sli4_hba.els_xri_cnt; +		lpfc_printf_log(phba, KERN_INFO, LOG_SLI, +				"3157 ELS xri-sgl count increased from " +				"%d to %d\n", phba->sli4_hba.els_xri_cnt, +				els_xri_cnt); +		/* allocate the additional els sgls */ +		for (i = 0; i < xri_cnt; i++) { +			sglq_entry = kzalloc(sizeof(struct lpfc_sglq), +					     GFP_KERNEL); +			if (sglq_entry == NULL) { +				lpfc_printf_log(phba, KERN_ERR, LOG_SLI, +						"2562 Failure to allocate an " +						"ELS sgl entry:%d\n", i); +				rc = -ENOMEM; +				goto out_free_mem; +			} +			sglq_entry->buff_type = GEN_BUFF_TYPE; +			sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, +							   &sglq_entry->phys); +			if (sglq_entry->virt == NULL) { +				kfree(sglq_entry); +				lpfc_printf_log(phba, KERN_ERR, LOG_SLI, +						"2563 Failure to allocate an " +						"ELS mbuf:%d\n", i); +				rc = -ENOMEM; +				goto out_free_mem; +			} +			sglq_entry->sgl = sglq_entry->virt; +			memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); +			sglq_entry->state = SGL_FREED; +			list_add_tail(&sglq_entry->list, &els_sgl_list); +		} +		spin_lock(&phba->hbalock); +		list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); +		spin_unlock(&phba->hbalock); +	} else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) { +		/* els xri-sgl shrinked */ +		xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt; +		lpfc_printf_log(phba, KERN_INFO, LOG_SLI, +				"3158 ELS xri-sgl count decreased from " +				"%d to %d\n", phba->sli4_hba.els_xri_cnt, +				els_xri_cnt); +		spin_lock_irq(&phba->hbalock); +		list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &els_sgl_list); +		spin_unlock_irq(&phba->hbalock); +		/* release extra els sgls from list */ +		for (i = 0; i < xri_cnt; i++) { +			list_remove_head(&els_sgl_list, +					 sglq_entry, struct lpfc_sglq, list); +			if (sglq_entry) { +				lpfc_mbuf_free(phba, sglq_entry->virt, +					       sglq_entry->phys); +				kfree(sglq_entry); +			} +		} +		spin_lock_irq(&phba->hbalock); +		list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); +		spin_unlock_irq(&phba->hbalock); +	} else +		lpfc_printf_log(phba, KERN_INFO, LOG_SLI, +				"3163 ELS xri-sgl count unchanged: %d\n", +				els_xri_cnt); +	phba->sli4_hba.els_xri_cnt = els_xri_cnt; + +	/* update xris to els sgls on the list */ +	sglq_entry = NULL; +	sglq_entry_next = NULL; +	list_for_each_entry_safe(sglq_entry, sglq_entry_next, +				 &phba->sli4_hba.lpfc_sgl_list, list) { +		lxri = lpfc_sli4_next_xritag(phba); +		if (lxri == NO_XRI) { +			lpfc_printf_log(phba, KERN_ERR, LOG_SLI, +					"2400 Failed to allocate xri for " +					"ELS sgl\n"); +			rc = -ENOMEM; +			goto out_free_mem; +		} +		sglq_entry->sli4_lxritag = lxri; +		sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; +	} + +	/* +	 * update on pci function's allocated scsi xri-sgl list +	 */ +	phba->total_scsi_bufs = 0; + +	/* maximum number of xris available for scsi buffers */ +	phba->sli4_hba.scsi_xri_max = phba->sli4_hba.max_cfg_param.max_xri - +				      els_xri_cnt; + +	lpfc_printf_log(phba, KERN_INFO, LOG_SLI, +			"2401 Current allocated SCSI xri-sgl count:%d, " +			"maximum  SCSI xri count:%d\n", +			phba->sli4_hba.scsi_xri_cnt, +			phba->sli4_hba.scsi_xri_max); + +	spin_lock_irq(&phba->scsi_buf_list_lock); +	list_splice_init(&phba->lpfc_scsi_buf_list, &scsi_sgl_list); +	spin_unlock_irq(&phba->scsi_buf_list_lock); + +	if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) { +		/* max scsi xri shrinked below the allocated scsi buffers */ +		scsi_xri_cnt = phba->sli4_hba.scsi_xri_cnt - +					phba->sli4_hba.scsi_xri_max; +		/* release the extra allocated scsi buffers */ +		for (i = 0; i < scsi_xri_cnt; i++) { +			list_remove_head(&scsi_sgl_list, psb, +					 struct lpfc_scsi_buf, list); +			pci_pool_free(phba->lpfc_scsi_dma_buf_pool, psb->data, +				      psb->dma_handle); +			kfree(psb); +		} +		spin_lock_irq(&phba->scsi_buf_list_lock); +		phba->sli4_hba.scsi_xri_cnt -= scsi_xri_cnt; +		spin_unlock_irq(&phba->scsi_buf_list_lock); +	} + +	/* update xris associated to remaining allocated scsi buffers */ +	psb = NULL; +	psb_next = NULL; +	list_for_each_entry_safe(psb, psb_next, &scsi_sgl_list, list) { +		lxri = lpfc_sli4_next_xritag(phba); +		if (lxri == NO_XRI) { +			lpfc_printf_log(phba, KERN_ERR, LOG_SLI, +					"2560 Failed to allocate xri for " +					"scsi buffer\n"); +			rc = -ENOMEM; +			goto out_free_mem; +		} +		psb->cur_iocbq.sli4_lxritag = lxri; +		psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; +	} +	spin_lock(&phba->scsi_buf_list_lock); +	list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list); +	spin_unlock(&phba->scsi_buf_list_lock); +  	return 0; + +out_free_mem: +	lpfc_free_els_sgl_list(phba); +	lpfc_scsi_free(phba); +	return rc;  }  /** @@ -4636,18 +4774,15 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  	if (rc)  		goto out_free_bsmbx; -	/* Initialize and populate the iocb list per host */ -	rc = lpfc_init_sgl_list(phba); -	if (rc) { -		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, -				"1400 Failed to initialize sgl list.\n"); -		goto out_destroy_cq_event_pool; -	} +	/* Initialize sgl lists per host */ +	lpfc_init_sgl_list(phba); + +	/* Allocate and initialize active sgl array */  	rc = lpfc_init_active_sgl_array(phba);  	if (rc) {  		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  				"1430 Failed to initialize sgl list.\n"); -		goto out_free_sgl_list; +		goto out_destroy_cq_event_pool;  	}  	rc = lpfc_sli4_init_rpi_hdrs(phba);  	if (rc) { @@ -4722,8 +4857,6 @@ out_remove_rpi_hdrs:  	lpfc_sli4_remove_rpi_hdrs(phba);  out_free_active_sgl:  	lpfc_free_active_sgl(phba); -out_free_sgl_list: -	lpfc_free_sgl_list(phba);  out_destroy_cq_event_pool:  	lpfc_sli4_cq_event_pool_destroy(phba);  out_free_bsmbx: @@ -4760,10 +4893,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)  	/* Free the ELS sgl list */  	lpfc_free_active_sgl(phba); -	lpfc_free_sgl_list(phba); - -	/* Free the SCSI sgl management array */ -	kfree(phba->sli4_hba.lpfc_scsi_psb_array); +	lpfc_free_els_sgl_list(phba);  	/* Free the completion queue EQ event pool */  	lpfc_sli4_cq_event_release_all(phba); @@ -4990,29 +5120,42 @@ out_free_iocbq:  }  /** - * lpfc_free_sgl_list - Free sgl list. + * lpfc_free_sgl_list - Free a given sgl list.   * @phba: pointer to lpfc hba data structure. + * @sglq_list: pointer to the head of sgl list.   * - * This routine is invoked to free the driver's sgl list and memory. + * This routine is invoked to free a give sgl list and memory.   **/ -static void -lpfc_free_sgl_list(struct lpfc_hba *phba) +void +lpfc_free_sgl_list(struct lpfc_hba *phba, struct list_head *sglq_list)  {  	struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + +	list_for_each_entry_safe(sglq_entry, sglq_next, sglq_list, list) { +		list_del(&sglq_entry->list); +		lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); +		kfree(sglq_entry); +	} +} + +/** + * lpfc_free_els_sgl_list - Free els sgl list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the driver's els sgl list and memory. + **/ +static void +lpfc_free_els_sgl_list(struct lpfc_hba *phba) +{  	LIST_HEAD(sglq_list); +	/* Retrieve all els sgls from driver list */  	spin_lock_irq(&phba->hbalock);  	list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list);  	spin_unlock_irq(&phba->hbalock); -	list_for_each_entry_safe(sglq_entry, sglq_next, -				 &sglq_list, list) { -		list_del(&sglq_entry->list); -		lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); -		kfree(sglq_entry); -		phba->sli4_hba.total_sglq_bufs--; -	} -	kfree(phba->sli4_hba.lpfc_els_sgl_array); +	/* Now free the sgl list */ +	lpfc_free_sgl_list(phba, &sglq_list);  }  /** @@ -5057,99 +5200,19 @@ lpfc_free_active_sgl(struct lpfc_hba *phba)   * This routine is invoked to allocate and initizlize the driver's sgl   * list and set up the sgl xritag tag array accordingly.   * - * Return codes - *	0 - successful - *	other values - error   **/ -static int +static void  lpfc_init_sgl_list(struct lpfc_hba *phba)  { -	struct lpfc_sglq *sglq_entry = NULL; -	int i; -	int els_xri_cnt; - -	els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); -	lpfc_printf_log(phba, KERN_INFO, LOG_SLI, -				"2400 ELS XRI count %d.\n", -				els_xri_cnt);  	/* Initialize and populate the sglq list per host/VF. */  	INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list);  	INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list); -	/* Sanity check on XRI management */ -	if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) { -		lpfc_printf_log(phba, KERN_ERR, LOG_SLI, -				"2562 No room left for SCSI XRI allocation: " -				"max_xri=%d, els_xri=%d\n", -				phba->sli4_hba.max_cfg_param.max_xri, -				els_xri_cnt); -		return -ENOMEM; -	} - -	/* Allocate memory for the ELS XRI management array */ -	phba->sli4_hba.lpfc_els_sgl_array = -			kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt), -			GFP_KERNEL); - -	if (!phba->sli4_hba.lpfc_els_sgl_array) { -		lpfc_printf_log(phba, KERN_ERR, LOG_SLI, -				"2401 Failed to allocate memory for ELS " -				"XRI management array of size %d.\n", -				els_xri_cnt); -		return -ENOMEM; -	} +	/* els xri-sgl book keeping */ +	phba->sli4_hba.els_xri_cnt = 0; -	/* Keep the SCSI XRI into the XRI management array */ -	phba->sli4_hba.scsi_xri_max = -			phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt; +	/* scsi xri-buffer book keeping */  	phba->sli4_hba.scsi_xri_cnt = 0; -	phba->sli4_hba.lpfc_scsi_psb_array = -			kzalloc((sizeof(struct lpfc_scsi_buf *) * -			phba->sli4_hba.scsi_xri_max), GFP_KERNEL); - -	if (!phba->sli4_hba.lpfc_scsi_psb_array) { -		lpfc_printf_log(phba, KERN_ERR, LOG_SLI, -				"2563 Failed to allocate memory for SCSI " -				"XRI management array of size %d.\n", -				phba->sli4_hba.scsi_xri_max); -		kfree(phba->sli4_hba.lpfc_els_sgl_array); -		return -ENOMEM; -	} - -	for (i = 0; i < els_xri_cnt; i++) { -		sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); -		if (sglq_entry == NULL) { -			printk(KERN_ERR "%s: only allocated %d sgls of " -				"expected %d count. Unloading driver.\n", -				__func__, i, els_xri_cnt); -			goto out_free_mem; -		} - -		sglq_entry->buff_type = GEN_BUFF_TYPE; -		sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys); -		if (sglq_entry->virt == NULL) { -			kfree(sglq_entry); -			printk(KERN_ERR "%s: failed to allocate mbuf.\n" -				"Unloading driver.\n", __func__); -			goto out_free_mem; -		} -		sglq_entry->sgl = sglq_entry->virt; -		memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); - -		/* The list order is used by later block SGL registraton */ -		spin_lock_irq(&phba->hbalock); -		sglq_entry->state = SGL_FREED; -		list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list); -		phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry; -		phba->sli4_hba.total_sglq_bufs++; -		spin_unlock_irq(&phba->hbalock); -	} -	return 0; - -out_free_mem: -	kfree(phba->sli4_hba.lpfc_scsi_psb_array); -	lpfc_free_sgl_list(phba); -	return -ENOMEM;  }  /** @@ -7320,9 +7383,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)  					phba->sli4_hba.u.if_type2.ERR2regaddr);  				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  					"2890 Port error detected during port " -					"reset(%d): port status reg 0x%x, " +					"reset(%d): wait_tmo:%d ms, " +					"port status reg 0x%x, "  					"error 1=0x%x, error 2=0x%x\n", -					num_resets, reg_data.word0, +					num_resets, rdy_chk*10, +					reg_data.word0,  					phba->work_status[0],  					phba->work_status[1]);  				rc = -ENODEV; @@ -8694,8 +8759,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)  	/* Release all the vports against this physical port */  	vports = lpfc_create_vport_work_array(phba);  	if (vports != NULL) -		for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) +		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { +			if (vports[i]->port_type == LPFC_PHYSICAL_PORT) +				continue;  			fc_vport_terminate(vports[i]->fc_vport); +		}  	lpfc_destroy_vport_work_array(phba, vports);  	/* Remove FC host and then SCSI host with the physical port */ @@ -9115,8 +9183,12 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)  			return 50;  		else if (max_xri <= 1024)  			return 100; -		else +		else if (max_xri <= 1536)  			return 150; +		else if (max_xri <= 2048) +			return 200; +		else +			return 250;  	} else  		return 0;  } @@ -9455,8 +9527,11 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)  	/* Release all the vports against this physical port */  	vports = lpfc_create_vport_work_array(phba);  	if (vports != NULL) -		for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) +		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { +			if (vports[i]->port_type == LPFC_PHYSICAL_PORT) +				continue;  			fc_vport_terminate(vports[i]->fc_vport); +		}  	lpfc_destroy_vport_work_array(phba, vports);  	/* Remove FC host and then SCSI host with the physical port */  |