forked from mirrors/linux
		
	SCSI misc on 20250529
Updates to the usual drivers (smartpqi, ufs, lpfc, scsi_debug, target, hisi_sas) with the only substantive core change being the removal of the stream_status member from the scsi_stream_status_header (to get rid of flex array members). Signed-off-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCaDiQ2CYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishWtDAP9p0Jd/ H4VMpYT5iETyq3TeAXTm1jVXL9Gnux5JMfskGwEA9kST8O6gorVOVKck+Eq0Hc9r w8NDnBK91hknIai5kE8= =/1L9 -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI updates from James Bottomley: "Updates to the usual drivers (smartpqi, ufs, lpfc, scsi_debug, target, hisi_sas) with the only substantive core change being the removal of the stream_status member from the scsi_stream_status_header (to get rid of flex array members)" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (77 commits) scsi: target: core: Constify struct target_opcode_descriptor scsi: target: core: Constify enabled() in struct target_opcode_descriptor scsi: hisi_sas: Fix warning detected by sparse scsi: mpt3sas: Fix _ctl_get_mpt_mctp_passthru_adapter() to return IOC pointer scsi: sg: Remove unnecessary NULL check before unregister_sysctl_table() scsi: ufs: mcq: Delete ufshcd_release_scsi_cmd() in ufshcd_mcq_abort() scsi: ufs: qcom: dt-bindings: Document the SM8750 UFS Controller scsi: mvsas: Fix typos in SAS/SATA VSP register comments scsi: fnic: Replace memset() with eth_zero_addr() scsi: ufs: core: Support updating device command timeout scsi: ufs: core: Change hwq_id type and value scsi: ufs: core: Increase the UIC command timeout further scsi: zfcp: Simplify workqueue allocation scsi: ufs: core: Print error value as hex format in ufshcd_err_handler() scsi: sd: Remove the stream_status member from scsi_stream_status_header scsi: docs: Clean up some style in scsi_mid_low_api scsi: core: Remove unused scsi_dev_info_list_del_keyed() scsi: isci: Remove unused sci_remote_device_reset() scsi: scsi_debug: Reduce DEF_ATOMIC_WR_MAX_LENGTH scsi: smartpqi: Delete a stray tab in pqi_is_parity_write_stream() ...
This commit is contained in:
		
						commit
						f66bc387ef
					
				
					 63 changed files with 1996 additions and 1829 deletions
				
			
		|  | @ -1636,3 +1636,52 @@ Description: | ||||||
| 		attribute value. | 		attribute value. | ||||||
| 
 | 
 | ||||||
| 		The attribute is read only. | 		The attribute is read only. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/platform/drivers/ufshcd/*/wb_resize_enable | ||||||
|  | What:		/sys/bus/platform/devices/*.ufs/wb_resize_enable | ||||||
|  | Date:		April 2025 | ||||||
|  | Contact:	Huan Tang <tanghuan@vivo.com> | ||||||
|  | Description: | ||||||
|  | 		The host can enable the WriteBooster buffer resize by setting this | ||||||
|  | 		attribute. | ||||||
|  | 
 | ||||||
|  | 		========  ====================================== | ||||||
|  | 		idle      There is no resize operation | ||||||
|  | 		decrease  Decrease WriteBooster buffer size | ||||||
|  | 		increase  Increase WriteBooster buffer size | ||||||
|  | 		========  ====================================== | ||||||
|  | 
 | ||||||
|  | 		The file is write only. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/platform/drivers/ufshcd/*/attributes/wb_resize_hint | ||||||
|  | What:		/sys/bus/platform/devices/*.ufs/attributes/wb_resize_hint | ||||||
|  | Date:		April 2025 | ||||||
|  | Contact:	Huan Tang <tanghuan@vivo.com> | ||||||
|  | Description: | ||||||
|  | 		wb_resize_hint indicates hint information about which type of resize | ||||||
|  | 		for WriteBooster buffer is recommended by the device. | ||||||
|  | 
 | ||||||
|  | 		=========  ====================================== | ||||||
|  | 		keep       Recommend keep the buffer size | ||||||
|  | 		decrease   Recommend to decrease the buffer size | ||||||
|  | 		increase   Recommend to increase the buffer size | ||||||
|  | 		=========  ====================================== | ||||||
|  | 
 | ||||||
|  | 		The file is read only. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/platform/drivers/ufshcd/*/attributes/wb_resize_status | ||||||
|  | What:		/sys/bus/platform/devices/*.ufs/attributes/wb_resize_status | ||||||
|  | Date:		April 2025 | ||||||
|  | Contact:	Huan Tang <tanghuan@vivo.com> | ||||||
|  | Description: | ||||||
|  | 		The host can check the resize operation status of the WriteBooster | ||||||
|  | 		buffer by reading this attribute. | ||||||
|  | 
 | ||||||
|  | 		================  ======================================== | ||||||
|  | 		idle              Resize operation is not issued | ||||||
|  | 		in_progress       Resize operation in progress | ||||||
|  | 		complete_success  Resize operation completed successfully | ||||||
|  | 		general_failure   Resize operation general failure | ||||||
|  | 		================  ======================================== | ||||||
|  | 
 | ||||||
|  | 		The file is read only. | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ properties: | ||||||
|           - qcom,sm8450-ufshc |           - qcom,sm8450-ufshc | ||||||
|           - qcom,sm8550-ufshc |           - qcom,sm8550-ufshc | ||||||
|           - qcom,sm8650-ufshc |           - qcom,sm8650-ufshc | ||||||
|  |           - qcom,sm8750-ufshc | ||||||
|       - const: qcom,ufshc |       - const: qcom,ufshc | ||||||
|       - const: jedec,ufs-2.0 |       - const: jedec,ufs-2.0 | ||||||
| 
 | 
 | ||||||
|  | @ -158,6 +159,7 @@ allOf: | ||||||
|               - qcom,sm8450-ufshc |               - qcom,sm8450-ufshc | ||||||
|               - qcom,sm8550-ufshc |               - qcom,sm8550-ufshc | ||||||
|               - qcom,sm8650-ufshc |               - qcom,sm8650-ufshc | ||||||
|  |               - qcom,sm8750-ufshc | ||||||
|     then: |     then: | ||||||
|       properties: |       properties: | ||||||
|         clocks: |         clocks: | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ ISA adapters).] | ||||||
| The SCSI mid level isolates an LLD from other layers such as the SCSI | The SCSI mid level isolates an LLD from other layers such as the SCSI | ||||||
| upper layer drivers and the block layer. | upper layer drivers and the block layer. | ||||||
| 
 | 
 | ||||||
| This version of the document roughly matches linux kernel version 2.6.8 . | This version of the document roughly matches Linux kernel version 2.6.8 . | ||||||
| 
 | 
 | ||||||
| Documentation | Documentation | ||||||
| ============= | ============= | ||||||
|  | @ -48,7 +48,7 @@ found in that directory. A more recent copy of this document may be found | ||||||
| at https://docs.kernel.org/scsi/scsi_mid_low_api.html. Many LLDs are | at https://docs.kernel.org/scsi/scsi_mid_low_api.html. Many LLDs are | ||||||
| documented in Documentation/scsi (e.g. aic7xxx.rst). The SCSI mid-level is | documented in Documentation/scsi (e.g. aic7xxx.rst). The SCSI mid-level is | ||||||
| briefly described in scsi.rst which contains a URL to a document describing | briefly described in scsi.rst which contains a URL to a document describing | ||||||
| the SCSI subsystem in the Linux Kernel 2.4 series. Two upper level | the SCSI subsystem in the Linux kernel 2.4 series. Two upper level | ||||||
| drivers have documents in that directory: st.rst (SCSI tape driver) and | drivers have documents in that directory: st.rst (SCSI tape driver) and | ||||||
| scsi-generic.rst (for the sg driver). | scsi-generic.rst (for the sg driver). | ||||||
| 
 | 
 | ||||||
|  | @ -75,7 +75,7 @@ It is probably best to study how existing LLDs are organized. | ||||||
| As the 2.5 series development kernels evolve into the 2.6 series | As the 2.5 series development kernels evolve into the 2.6 series | ||||||
| production series, changes are being introduced into this interface. An | production series, changes are being introduced into this interface. An | ||||||
| example of this is driver initialization code where there are now 2 models | example of this is driver initialization code where there are now 2 models | ||||||
| available. The older one, similar to what was found in the lk 2.4 series, | available. The older one, similar to what was found in the Linux 2.4 series, | ||||||
| is based on hosts that are detected at HBA driver load time. This will be | is based on hosts that are detected at HBA driver load time. This will be | ||||||
| referred to the "passive" initialization model. The newer model allows HBAs | referred to the "passive" initialization model. The newer model allows HBAs | ||||||
| to be hot plugged (and unplugged) during the lifetime of the LLD and will | to be hot plugged (and unplugged) during the lifetime of the LLD and will | ||||||
|  | @ -1026,7 +1026,7 @@ initialized from the driver's struct scsi_host_template instance. Members | ||||||
| of interest: | of interest: | ||||||
| 
 | 
 | ||||||
|     host_no |     host_no | ||||||
| 		 - system wide unique number that is used for identifying | 		 - system-wide unique number that is used for identifying | ||||||
|                    this host. Issued in ascending order from 0. |                    this host. Issued in ascending order from 0. | ||||||
|     can_queue |     can_queue | ||||||
| 		 - must be greater than 0; do not send more than can_queue | 		 - must be greater than 0; do not send more than can_queue | ||||||
|  | @ -1053,7 +1053,7 @@ of interest: | ||||||
| 		 - pointer to driver's struct scsi_host_template from which | 		 - pointer to driver's struct scsi_host_template from which | ||||||
|                    this struct Scsi_Host instance was spawned |                    this struct Scsi_Host instance was spawned | ||||||
|     hostt->proc_name |     hostt->proc_name | ||||||
| 		 - name of LLD. This is the driver name that sysfs uses | 		 - name of LLD. This is the driver name that sysfs uses. | ||||||
|     transportt |     transportt | ||||||
| 		 - pointer to driver's struct scsi_transport_template instance | 		 - pointer to driver's struct scsi_transport_template instance | ||||||
|                    (if any). FC and SPI transports currently supported. |                    (if any). FC and SPI transports currently supported. | ||||||
|  | @ -1067,7 +1067,7 @@ The scsi_host structure is defined in include/scsi/scsi_host.h | ||||||
| struct scsi_device | struct scsi_device | ||||||
| ------------------ | ------------------ | ||||||
| Generally, there is one instance of this structure for each SCSI logical unit | Generally, there is one instance of this structure for each SCSI logical unit | ||||||
| on a host. Scsi devices connected to a host are uniquely identified by a | on a host. SCSI devices connected to a host are uniquely identified by a | ||||||
| channel number, target id and logical unit number (lun). | channel number, target id and logical unit number (lun). | ||||||
| The structure is defined in include/scsi/scsi_device.h | The structure is defined in include/scsi/scsi_device.h | ||||||
| 
 | 
 | ||||||
|  | @ -1091,7 +1091,7 @@ Members of interest: | ||||||
| 		 - should be set by LLD prior to calling 'done'. A value | 		 - should be set by LLD prior to calling 'done'. A value | ||||||
|                    of 0 implies a successfully completed command (and all |                    of 0 implies a successfully completed command (and all | ||||||
|                    data (if any) has been transferred to or from the SCSI |                    data (if any) has been transferred to or from the SCSI | ||||||
|                    target device). 'result' is a 32 bit unsigned integer that |                    target device). 'result' is a 32-bit unsigned integer that | ||||||
|                    can be viewed as 2 related bytes. The SCSI status value is |                    can be viewed as 2 related bytes. The SCSI status value is | ||||||
|                    in the LSB. See include/scsi/scsi.h status_byte() and |                    in the LSB. See include/scsi/scsi.h status_byte() and | ||||||
|                    host_byte() macros and related constants. |                    host_byte() macros and related constants. | ||||||
|  | @ -1180,8 +1180,8 @@ may get out of synchronization. This is why it is best for the LLD | ||||||
| to perform autosense. | to perform autosense. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Changes since lk 2.4 series | Changes since Linux kernel 2.4 series | ||||||
| =========================== | ===================================== | ||||||
| io_request_lock has been replaced by several finer grained locks. The lock | io_request_lock has been replaced by several finer grained locks. The lock | ||||||
| relevant to LLDs is struct Scsi_Host::host_lock and there is | relevant to LLDs is struct Scsi_Host::host_lock and there is | ||||||
| one per SCSI host. | one per SCSI host. | ||||||
|  |  | ||||||
|  | @ -1882,6 +1882,11 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, | ||||||
| 	if (IS_ERR_OR_NULL(ice)) | 	if (IS_ERR_OR_NULL(ice)) | ||||||
| 		return PTR_ERR_OR_ZERO(ice); | 		return PTR_ERR_OR_ZERO(ice); | ||||||
| 
 | 
 | ||||||
|  | 	if (qcom_ice_get_supported_key_type(ice) != BLK_CRYPTO_KEY_TYPE_RAW) { | ||||||
|  | 		dev_warn(dev, "Wrapped keys not supported. Disabling inline encryption support.\n"); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	msm_host->ice = ice; | 	msm_host->ice = ice; | ||||||
| 
 | 
 | ||||||
| 	/* Initialize the blk_crypto_profile */ | 	/* Initialize the blk_crypto_profile */ | ||||||
|  | @ -1962,16 +1967,7 @@ static int sdhci_msm_ice_keyslot_program(struct blk_crypto_profile *profile, | ||||||
| 	struct sdhci_msm_host *msm_host = | 	struct sdhci_msm_host *msm_host = | ||||||
| 		sdhci_msm_host_from_crypto_profile(profile); | 		sdhci_msm_host_from_crypto_profile(profile); | ||||||
| 
 | 
 | ||||||
| 	/* Only AES-256-XTS has been tested so far. */ | 	return qcom_ice_program_key(msm_host->ice, slot, key); | ||||||
| 	if (key->crypto_cfg.crypto_mode != BLK_ENCRYPTION_MODE_AES_256_XTS) |  | ||||||
| 		return -EOPNOTSUPP; |  | ||||||
| 
 |  | ||||||
| 	return qcom_ice_program_key(msm_host->ice, |  | ||||||
| 				    QCOM_ICE_CRYPTO_ALG_AES_XTS, |  | ||||||
| 				    QCOM_ICE_CRYPTO_KEY_SIZE_256, |  | ||||||
| 				    key->bytes, |  | ||||||
| 				    key->crypto_cfg.data_unit_size / 512, |  | ||||||
| 				    slot); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int sdhci_msm_ice_keyslot_evict(struct blk_crypto_profile *profile, | static int sdhci_msm_ice_keyslot_evict(struct blk_crypto_profile *profile, | ||||||
|  |  | ||||||
|  | @ -312,15 +312,13 @@ static void zfcp_print_sl(struct seq_file *m, struct service_level *sl) | ||||||
| 
 | 
 | ||||||
| static int zfcp_setup_adapter_work_queue(struct zfcp_adapter *adapter) | static int zfcp_setup_adapter_work_queue(struct zfcp_adapter *adapter) | ||||||
| { | { | ||||||
| 	char name[TASK_COMM_LEN]; | 	adapter->work_queue = | ||||||
|  | 		alloc_ordered_workqueue("zfcp_q_%s", WQ_MEM_RECLAIM, | ||||||
|  | 					dev_name(&adapter->ccw_device->dev)); | ||||||
|  | 	if (!adapter->work_queue) | ||||||
|  | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	snprintf(name, sizeof(name), "zfcp_q_%s", | 	return 0; | ||||||
| 		 dev_name(&adapter->ccw_device->dev)); |  | ||||||
| 	adapter->work_queue = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); |  | ||||||
| 
 |  | ||||||
| 	if (adapter->work_queue) |  | ||||||
| 		return 0; |  | ||||||
| 	return -ENOMEM; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) | static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -3804,7 +3804,7 @@ sli_cmd_common_write_object(struct sli4 *sli4, void *buf, u16 noc, | ||||||
| 	wr_obj->desired_write_len_dword = cpu_to_le32(dwflags); | 	wr_obj->desired_write_len_dword = cpu_to_le32(dwflags); | ||||||
| 
 | 
 | ||||||
| 	wr_obj->write_offset = cpu_to_le32(offset); | 	wr_obj->write_offset = cpu_to_le32(offset); | ||||||
| 	strncpy(wr_obj->object_name, obj_name, sizeof(wr_obj->object_name) - 1); | 	strscpy(wr_obj->object_name, obj_name); | ||||||
| 	wr_obj->host_buffer_descriptor_count = cpu_to_le32(1); | 	wr_obj->host_buffer_descriptor_count = cpu_to_le32(1); | ||||||
| 
 | 
 | ||||||
| 	bde = (struct sli4_bde *)wr_obj->host_buffer_descriptor; | 	bde = (struct sli4_bde *)wr_obj->host_buffer_descriptor; | ||||||
|  | @ -3833,7 +3833,7 @@ sli_cmd_common_delete_object(struct sli4 *sli4, void *buf, char *obj_name) | ||||||
| 			 SLI4_SUBSYSTEM_COMMON, CMD_V0, | 			 SLI4_SUBSYSTEM_COMMON, CMD_V0, | ||||||
| 			 SLI4_RQST_PYLD_LEN(cmn_delete_object)); | 			 SLI4_RQST_PYLD_LEN(cmn_delete_object)); | ||||||
| 
 | 
 | ||||||
| 	strncpy(req->object_name, obj_name, sizeof(req->object_name) - 1); | 	strscpy(req->object_name, obj_name); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -3856,7 +3856,7 @@ sli_cmd_common_read_object(struct sli4 *sli4, void *buf, u32 desired_read_len, | ||||||
| 		cpu_to_le32(desired_read_len & SLI4_REQ_DESIRE_READLEN); | 		cpu_to_le32(desired_read_len & SLI4_REQ_DESIRE_READLEN); | ||||||
| 
 | 
 | ||||||
| 	rd_obj->read_offset = cpu_to_le32(offset); | 	rd_obj->read_offset = cpu_to_le32(offset); | ||||||
| 	strncpy(rd_obj->object_name, obj_name, sizeof(rd_obj->object_name) - 1); | 	strscpy(rd_obj->object_name, obj_name); | ||||||
| 	rd_obj->host_buffer_descriptor_count = cpu_to_le32(1); | 	rd_obj->host_buffer_descriptor_count = cpu_to_le32(1); | ||||||
| 
 | 
 | ||||||
| 	bde = (struct sli4_bde *)rd_obj->host_buffer_descriptor; | 	bde = (struct sli4_bde *)rd_obj->host_buffer_descriptor; | ||||||
|  |  | ||||||
|  | @ -200,7 +200,7 @@ void fnic_fcoe_start_fcf_discovery(struct fnic *fnic) | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	memset(iport->selected_fcf.fcf_mac, 0, ETH_ALEN); | 	eth_zero_addr(iport->selected_fcf.fcf_mac); | ||||||
| 
 | 
 | ||||||
| 	pdisc_sol = (struct fip_discovery *) frame; | 	pdisc_sol = (struct fip_discovery *) frame; | ||||||
| 	*pdisc_sol = (struct fip_discovery) { | 	*pdisc_sol = (struct fip_discovery) { | ||||||
|  | @ -588,12 +588,12 @@ void fnic_common_fip_cleanup(struct fnic *fnic) | ||||||
| 	if (!is_zero_ether_addr(iport->fpma)) | 	if (!is_zero_ether_addr(iport->fpma)) | ||||||
| 		vnic_dev_del_addr(fnic->vdev, iport->fpma); | 		vnic_dev_del_addr(fnic->vdev, iport->fpma); | ||||||
| 
 | 
 | ||||||
| 	memset(iport->fpma, 0, ETH_ALEN); | 	eth_zero_addr(iport->fpma); | ||||||
| 	iport->fcid = 0; | 	iport->fcid = 0; | ||||||
| 	iport->r_a_tov = 0; | 	iport->r_a_tov = 0; | ||||||
| 	iport->e_d_tov = 0; | 	iport->e_d_tov = 0; | ||||||
| 	memset(fnic->iport.fcfmac, 0, ETH_ALEN); | 	eth_zero_addr(fnic->iport.fcfmac); | ||||||
| 	memset(iport->selected_fcf.fcf_mac, 0, ETH_ALEN); | 	eth_zero_addr(iport->selected_fcf.fcf_mac); | ||||||
| 	iport->selected_fcf.fcf_priority = 0; | 	iport->selected_fcf.fcf_priority = 0; | ||||||
| 	iport->selected_fcf.fka_adv_period = 0; | 	iport->selected_fcf.fka_adv_period = 0; | ||||||
| 	iport->selected_fcf.ka_disabled = 0; | 	iport->selected_fcf.ka_disabled = 0; | ||||||
|  |  | ||||||
|  | @ -46,6 +46,13 @@ | ||||||
| #define HISI_SAS_IOST_ITCT_CACHE_DW_SZ 10 | #define HISI_SAS_IOST_ITCT_CACHE_DW_SZ 10 | ||||||
| #define HISI_SAS_FIFO_DATA_DW_SIZE 32 | #define HISI_SAS_FIFO_DATA_DW_SIZE 32 | ||||||
| 
 | 
 | ||||||
|  | #define HISI_SAS_REG_MEM_SIZE 4 | ||||||
|  | #define HISI_SAS_MAX_CDB_LEN 16 | ||||||
|  | #define HISI_SAS_BLK_QUEUE_DEPTH 64 | ||||||
|  | 
 | ||||||
|  | #define BYTE_TO_DW 4 | ||||||
|  | #define BYTE_TO_DDW 8 | ||||||
|  | 
 | ||||||
| #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer)) | #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer)) | ||||||
| #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table)) | #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table)) | ||||||
| 
 | 
 | ||||||
|  | @ -92,6 +99,8 @@ | ||||||
| 
 | 
 | ||||||
| #define HISI_SAS_WAIT_PHYUP_TIMEOUT	(30 * HZ) | #define HISI_SAS_WAIT_PHYUP_TIMEOUT	(30 * HZ) | ||||||
| #define HISI_SAS_CLEAR_ITCT_TIMEOUT	(20 * HZ) | #define HISI_SAS_CLEAR_ITCT_TIMEOUT	(20 * HZ) | ||||||
|  | #define HISI_SAS_DELAY_FOR_PHY_DISABLE 100 | ||||||
|  | #define NAME_BUF_SIZE 256 | ||||||
| 
 | 
 | ||||||
| struct hisi_hba; | struct hisi_hba; | ||||||
| 
 | 
 | ||||||
|  | @ -167,6 +176,8 @@ struct hisi_sas_debugfs_fifo { | ||||||
| 	u32 rd_data[HISI_SAS_FIFO_DATA_DW_SIZE]; | 	u32 rd_data[HISI_SAS_FIFO_DATA_DW_SIZE]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define FRAME_RCVD_BUF 32 | ||||||
|  | #define SAS_PHY_RESV_SIZE 2 | ||||||
| struct hisi_sas_phy { | struct hisi_sas_phy { | ||||||
| 	struct work_struct	works[HISI_PHYES_NUM]; | 	struct work_struct	works[HISI_PHYES_NUM]; | ||||||
| 	struct hisi_hba	*hisi_hba; | 	struct hisi_hba	*hisi_hba; | ||||||
|  | @ -178,10 +189,10 @@ struct hisi_sas_phy { | ||||||
| 	spinlock_t lock; | 	spinlock_t lock; | ||||||
| 	u64		port_id; /* from hw */ | 	u64		port_id; /* from hw */ | ||||||
| 	u64		frame_rcvd_size; | 	u64		frame_rcvd_size; | ||||||
| 	u8		frame_rcvd[32]; | 	u8		frame_rcvd[FRAME_RCVD_BUF]; | ||||||
| 	u8		phy_attached; | 	u8		phy_attached; | ||||||
| 	u8		in_reset; | 	u8		in_reset; | ||||||
| 	u8		reserved[2]; | 	u8		reserved[SAS_PHY_RESV_SIZE]; | ||||||
| 	u32		phy_type; | 	u32		phy_type; | ||||||
| 	u32		code_violation_err_count; | 	u32		code_violation_err_count; | ||||||
| 	enum sas_linkrate	minimum_linkrate; | 	enum sas_linkrate	minimum_linkrate; | ||||||
|  | @ -348,7 +359,8 @@ struct hisi_sas_hw { | ||||||
| 	const struct scsi_host_template *sht; | 	const struct scsi_host_template *sht; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define HISI_SAS_MAX_DEBUGFS_DUMP (50) | #define HISI_SAS_MAX_DEBUGFS_DUMP 50 | ||||||
|  | #define HISI_SAS_DEFAULT_DEBUGFS_DUMP 1 | ||||||
| 
 | 
 | ||||||
| struct hisi_sas_debugfs_cq { | struct hisi_sas_debugfs_cq { | ||||||
| 	struct hisi_sas_cq *cq; | 	struct hisi_sas_cq *cq; | ||||||
|  | @ -448,12 +460,12 @@ struct hisi_hba { | ||||||
| 	dma_addr_t sata_breakpoint_dma; | 	dma_addr_t sata_breakpoint_dma; | ||||||
| 	struct hisi_sas_slot	*slot_info; | 	struct hisi_sas_slot	*slot_info; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	const struct hisi_sas_hw *hw;	/* Low level hw interface */ | 	const struct hisi_sas_hw *hw; /* Low level hw interface */ | ||||||
| 	unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; | 	unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; | ||||||
| 	struct work_struct rst_work; | 	struct work_struct rst_work; | ||||||
| 	u32 phy_state; | 	u32 phy_state; | ||||||
| 	u32 intr_coal_ticks;	/* Time of interrupt coalesce in us */ | 	u32 intr_coal_ticks; /* Time of interrupt coalesce in us */ | ||||||
| 	u32 intr_coal_count;	/* Interrupt count to coalesce */ | 	u32 intr_coal_count; /* Interrupt count to coalesce */ | ||||||
| 
 | 
 | ||||||
| 	int cq_nvecs; | 	int cq_nvecs; | ||||||
| 
 | 
 | ||||||
|  | @ -528,12 +540,13 @@ struct hisi_sas_cmd_hdr { | ||||||
| 	__le64 dif_prd_table_addr; | 	__le64 dif_prd_table_addr; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define ITCT_RESV_DDW 12 | ||||||
| struct hisi_sas_itct { | struct hisi_sas_itct { | ||||||
| 	__le64 qw0; | 	__le64 qw0; | ||||||
| 	__le64 sas_addr; | 	__le64 sas_addr; | ||||||
| 	__le64 qw2; | 	__le64 qw2; | ||||||
| 	__le64 qw3; | 	__le64 qw3; | ||||||
| 	__le64 qw4_15[12]; | 	__le64 qw4_15[ITCT_RESV_DDW]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hisi_sas_iost { | struct hisi_sas_iost { | ||||||
|  | @ -543,22 +556,26 @@ struct hisi_sas_iost { | ||||||
| 	__le64 qw3; | 	__le64 qw3; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define ERROR_RECORD_BUF_DW 4 | ||||||
| struct hisi_sas_err_record { | struct hisi_sas_err_record { | ||||||
| 	u32	data[4]; | 	u32	data[ERROR_RECORD_BUF_DW]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define FIS_RESV_DW 3 | ||||||
| struct hisi_sas_initial_fis { | struct hisi_sas_initial_fis { | ||||||
| 	struct hisi_sas_err_record err_record; | 	struct hisi_sas_err_record err_record; | ||||||
| 	struct dev_to_host_fis fis; | 	struct dev_to_host_fis fis; | ||||||
| 	u32 rsvd[3]; | 	u32 rsvd[FIS_RESV_DW]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define BREAKPOINT_DATA_SIZE 128 | ||||||
| struct hisi_sas_breakpoint { | struct hisi_sas_breakpoint { | ||||||
| 	u8	data[128]; | 	u8	data[BREAKPOINT_DATA_SIZE]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define BREAKPOINT_TAG_NUM 32 | ||||||
| struct hisi_sas_sata_breakpoint { | struct hisi_sas_sata_breakpoint { | ||||||
| 	struct hisi_sas_breakpoint tag[32]; | 	struct hisi_sas_breakpoint tag[BREAKPOINT_TAG_NUM]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hisi_sas_sge { | struct hisi_sas_sge { | ||||||
|  | @ -569,13 +586,15 @@ struct hisi_sas_sge { | ||||||
| 	__le32 data_off; | 	__le32 data_off; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define SMP_CMD_TABLE_SIZE 44 | ||||||
| struct hisi_sas_command_table_smp { | struct hisi_sas_command_table_smp { | ||||||
| 	u8 bytes[44]; | 	u8 bytes[SMP_CMD_TABLE_SIZE]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define DUMMY_BUF_SIZE 12 | ||||||
| struct hisi_sas_command_table_stp { | struct hisi_sas_command_table_stp { | ||||||
| 	struct	host_to_dev_fis command_fis; | 	struct	host_to_dev_fis command_fis; | ||||||
| 	u8	dummy[12]; | 	u8	dummy[DUMMY_BUF_SIZE]; | ||||||
| 	u8	atapi_cdb[ATAPI_CDB_LEN]; | 	u8	atapi_cdb[ATAPI_CDB_LEN]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -589,12 +608,13 @@ struct hisi_sas_sge_dif_page { | ||||||
| 	struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT]; | 	struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT]; | ||||||
| }  __aligned(16); | }  __aligned(16); | ||||||
| 
 | 
 | ||||||
|  | #define PROT_BUF_SIZE 7 | ||||||
| struct hisi_sas_command_table_ssp { | struct hisi_sas_command_table_ssp { | ||||||
| 	struct ssp_frame_hdr hdr; | 	struct ssp_frame_hdr hdr; | ||||||
| 	union { | 	union { | ||||||
| 		struct { | 		struct { | ||||||
| 			struct ssp_command_iu task; | 			struct ssp_command_iu task; | ||||||
| 			u32 prot[7]; | 			u32 prot[PROT_BUF_SIZE]; | ||||||
| 		}; | 		}; | ||||||
| 		struct ssp_tmf_iu ssp_task; | 		struct ssp_tmf_iu ssp_task; | ||||||
| 		struct xfer_rdy_iu xfer_rdy; | 		struct xfer_rdy_iu xfer_rdy; | ||||||
|  | @ -608,9 +628,10 @@ union hisi_sas_command_table { | ||||||
| 	struct hisi_sas_command_table_stp stp; | 	struct hisi_sas_command_table_stp stp; | ||||||
| }  __aligned(16); | }  __aligned(16); | ||||||
| 
 | 
 | ||||||
|  | #define IU_BUF_SIZE 1024 | ||||||
| struct hisi_sas_status_buffer { | struct hisi_sas_status_buffer { | ||||||
| 	struct hisi_sas_err_record err; | 	struct hisi_sas_err_record err; | ||||||
| 	u8	iu[1024]; | 	u8	iu[IU_BUF_SIZE]; | ||||||
| }  __aligned(16); | }  __aligned(16); | ||||||
| 
 | 
 | ||||||
| struct hisi_sas_slot_buf_table { | struct hisi_sas_slot_buf_table { | ||||||
|  |  | ||||||
|  | @ -7,6 +7,16 @@ | ||||||
| #include "hisi_sas.h" | #include "hisi_sas.h" | ||||||
| #define DRV_NAME "hisi_sas" | #define DRV_NAME "hisi_sas" | ||||||
| 
 | 
 | ||||||
|  | #define LINK_RATE_BIT_MASK 2 | ||||||
|  | #define FIS_BUF_SIZE 20 | ||||||
|  | #define WAIT_CMD_COMPLETE_DELAY 100 | ||||||
|  | #define WAIT_CMD_COMPLETE_TMROUT 5000 | ||||||
|  | #define DELAY_FOR_LINK_READY 2000 | ||||||
|  | #define BLK_CNT_OPTIMIZE_MARK 64 | ||||||
|  | #define HZ_TO_MHZ 1000000 | ||||||
|  | #define DELAY_FOR_SOFTRESET_MAX 1000 | ||||||
|  | #define DELAY_FOR_SOFTRESET_MIN 900 | ||||||
|  | 
 | ||||||
| #define DEV_IS_GONE(dev) \ | #define DEV_IS_GONE(dev) \ | ||||||
| 	((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) | 	((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) | ||||||
| 
 | 
 | ||||||
|  | @ -114,12 +124,10 @@ u8 hisi_sas_get_ata_protocol(struct sas_task *task) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	default: | 	default: | ||||||
| 	{ |  | ||||||
| 		if (direction == DMA_NONE) | 		if (direction == DMA_NONE) | ||||||
| 			return HISI_SAS_SATA_PROTOCOL_NONDATA; | 			return HISI_SAS_SATA_PROTOCOL_NONDATA; | ||||||
| 		return hisi_sas_get_ata_protocol_from_tf(qc); | 		return hisi_sas_get_ata_protocol_from_tf(qc); | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol); | EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol); | ||||||
| 
 | 
 | ||||||
|  | @ -131,7 +139,7 @@ void hisi_sas_sata_done(struct sas_task *task, | ||||||
| 	struct hisi_sas_status_buffer *status_buf = | 	struct hisi_sas_status_buffer *status_buf = | ||||||
| 			hisi_sas_status_buf_addr_mem(slot); | 			hisi_sas_status_buf_addr_mem(slot); | ||||||
| 	u8 *iu = &status_buf->iu[0]; | 	u8 *iu = &status_buf->iu[0]; | ||||||
| 	struct dev_to_host_fis *d2h =  (struct dev_to_host_fis *)iu; | 	struct dev_to_host_fis *d2h = (struct dev_to_host_fis *)iu; | ||||||
| 
 | 
 | ||||||
| 	resp->frame_len = sizeof(struct dev_to_host_fis); | 	resp->frame_len = sizeof(struct dev_to_host_fis); | ||||||
| 	memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis)); | 	memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis)); | ||||||
|  | @ -151,7 +159,7 @@ u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max) | ||||||
| 
 | 
 | ||||||
| 	max -= SAS_LINK_RATE_1_5_GBPS; | 	max -= SAS_LINK_RATE_1_5_GBPS; | ||||||
| 	for (i = 0; i <= max; i++) | 	for (i = 0; i <= max; i++) | ||||||
| 		rate |= 1 << (i * 2); | 		rate |= 1 << (i * LINK_RATE_BIT_MASK); | ||||||
| 	return rate; | 	return rate; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(hisi_sas_get_prog_phy_linkrate_mask); | EXPORT_SYMBOL_GPL(hisi_sas_get_prog_phy_linkrate_mask); | ||||||
|  | @ -900,7 +908,7 @@ int hisi_sas_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 	if (!dev_is_sata(dev)) | 	if (!dev_is_sata(dev)) | ||||||
| 		sas_change_queue_depth(sdev, 64); | 		sas_change_queue_depth(sdev, HISI_SAS_BLK_QUEUE_DEPTH); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -1262,7 +1270,7 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, | ||||||
| 	sas_phy->phy->minimum_linkrate = min; | 	sas_phy->phy->minimum_linkrate = min; | ||||||
| 
 | 
 | ||||||
| 	hisi_sas_phy_enable(hisi_hba, phy_no, 0); | 	hisi_sas_phy_enable(hisi_hba, phy_no, 0); | ||||||
| 	msleep(100); | 	msleep(HISI_SAS_DELAY_FOR_PHY_DISABLE); | ||||||
| 	hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r); | 	hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r); | ||||||
| 	hisi_sas_phy_enable(hisi_hba, phy_no, 1); | 	hisi_sas_phy_enable(hisi_hba, phy_no, 1); | ||||||
| 
 | 
 | ||||||
|  | @ -1292,7 +1300,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, | ||||||
| 
 | 
 | ||||||
| 	case PHY_FUNC_LINK_RESET: | 	case PHY_FUNC_LINK_RESET: | ||||||
| 		hisi_sas_phy_enable(hisi_hba, phy_no, 0); | 		hisi_sas_phy_enable(hisi_hba, phy_no, 0); | ||||||
| 		msleep(100); | 		msleep(HISI_SAS_DELAY_FOR_PHY_DISABLE); | ||||||
| 		hisi_sas_phy_enable(hisi_hba, phy_no, 1); | 		hisi_sas_phy_enable(hisi_hba, phy_no, 1); | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
|  | @ -1347,7 +1355,7 @@ static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, | ||||||
| 
 | 
 | ||||||
| static int hisi_sas_softreset_ata_disk(struct domain_device *device) | static int hisi_sas_softreset_ata_disk(struct domain_device *device) | ||||||
| { | { | ||||||
| 	u8 fis[20] = {0}; | 	u8 fis[FIS_BUF_SIZE] = {0}; | ||||||
| 	struct ata_port *ap = device->sata_dev.ap; | 	struct ata_port *ap = device->sata_dev.ap; | ||||||
| 	struct ata_link *link; | 	struct ata_link *link; | ||||||
| 	int rc = TMF_RESP_FUNC_FAILED; | 	int rc = TMF_RESP_FUNC_FAILED; | ||||||
|  | @ -1364,7 +1372,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (rc == TMF_RESP_FUNC_COMPLETE) { | 	if (rc == TMF_RESP_FUNC_COMPLETE) { | ||||||
| 		usleep_range(900, 1000); | 		usleep_range(DELAY_FOR_SOFTRESET_MIN, DELAY_FOR_SOFTRESET_MAX); | ||||||
| 		ata_for_each_link(link, ap, EDGE) { | 		ata_for_each_link(link, ap, EDGE) { | ||||||
| 			int pmp = sata_srst_pmp(link); | 			int pmp = sata_srst_pmp(link); | ||||||
| 
 | 
 | ||||||
|  | @ -1494,7 +1502,7 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, | ||||||
| 	struct device *dev = hisi_hba->dev; | 	struct device *dev = hisi_hba->dev; | ||||||
| 	int rc = TMF_RESP_FUNC_FAILED; | 	int rc = TMF_RESP_FUNC_FAILED; | ||||||
| 	struct ata_link *link; | 	struct ata_link *link; | ||||||
| 	u8 fis[20] = {0}; | 	u8 fis[FIS_BUF_SIZE] = {0}; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < hisi_hba->n_phy; i++) { | 	for (i = 0; i < hisi_hba->n_phy; i++) { | ||||||
|  | @ -1561,7 +1569,9 @@ void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba) | ||||||
| 	hisi_hba->phy_state = hisi_hba->hw->get_phys_state(hisi_hba); | 	hisi_hba->phy_state = hisi_hba->hw->get_phys_state(hisi_hba); | ||||||
| 
 | 
 | ||||||
| 	scsi_block_requests(shost); | 	scsi_block_requests(shost); | ||||||
| 	hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000); | 	hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, | ||||||
|  | 						 WAIT_CMD_COMPLETE_DELAY, | ||||||
|  | 						 WAIT_CMD_COMPLETE_TMROUT); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * hisi_hba->timer is only used for v1/v2 hw, and check hw->sht | 	 * hisi_hba->timer is only used for v1/v2 hw, and check hw->sht | ||||||
|  | @ -1862,7 +1872,7 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) | ||||||
| 		rc = ata_wait_after_reset(link, jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT, | 		rc = ata_wait_after_reset(link, jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT, | ||||||
| 					  smp_ata_check_ready_type); | 					  smp_ata_check_ready_type); | ||||||
| 	} else { | 	} else { | ||||||
| 		msleep(2000); | 		msleep(DELAY_FOR_LINK_READY); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return rc; | 	return rc; | ||||||
|  | @ -1885,33 +1895,14 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) | ||||||
| 	} | 	} | ||||||
| 	hisi_sas_dereg_device(hisi_hba, device); | 	hisi_sas_dereg_device(hisi_hba, device); | ||||||
| 
 | 
 | ||||||
| 	rc = hisi_sas_debug_I_T_nexus_reset(device); | 	if (dev_is_sata(device)) { | ||||||
| 	if (rc == TMF_RESP_FUNC_COMPLETE && dev_is_sata(device)) { |  | ||||||
| 		struct sas_phy *local_phy; |  | ||||||
| 
 |  | ||||||
| 		rc = hisi_sas_softreset_ata_disk(device); | 		rc = hisi_sas_softreset_ata_disk(device); | ||||||
| 		switch (rc) { | 		if (rc == TMF_RESP_FUNC_FAILED) | ||||||
| 		case -ECOMM: | 			dev_err(dev, "ata disk %016llx reset (%d)\n", | ||||||
| 			rc = -ENODEV; | 				SAS_ADDR(device->sas_addr), rc); | ||||||
| 			break; |  | ||||||
| 		case TMF_RESP_FUNC_FAILED: |  | ||||||
| 		case -EMSGSIZE: |  | ||||||
| 		case -EIO: |  | ||||||
| 			local_phy = sas_get_local_phy(device); |  | ||||||
| 			rc = sas_phy_enable(local_phy, 0); |  | ||||||
| 			if (!rc) { |  | ||||||
| 				local_phy->enabled = 0; |  | ||||||
| 				dev_err(dev, "Disabled local phy of ATA disk %016llx due to softreset fail (%d)\n", |  | ||||||
| 					SAS_ADDR(device->sas_addr), rc); |  | ||||||
| 				rc = -ENODEV; |  | ||||||
| 			} |  | ||||||
| 			sas_put_local_phy(local_phy); |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	rc = hisi_sas_debug_I_T_nexus_reset(device); | ||||||
| 	if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV)) | 	if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV)) | ||||||
| 		hisi_sas_release_task(hisi_hba, device); | 		hisi_sas_release_task(hisi_hba, device); | ||||||
| 
 | 
 | ||||||
|  | @ -1934,12 +1925,9 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) | ||||||
| 	hisi_sas_dereg_device(hisi_hba, device); | 	hisi_sas_dereg_device(hisi_hba, device); | ||||||
| 
 | 
 | ||||||
| 	if (dev_is_sata(device)) { | 	if (dev_is_sata(device)) { | ||||||
| 		struct sas_phy *phy; | 		struct sas_phy *phy = sas_get_local_phy(device); | ||||||
| 
 |  | ||||||
| 		phy = sas_get_local_phy(device); |  | ||||||
| 
 | 
 | ||||||
| 		rc = sas_phy_reset(phy, true); | 		rc = sas_phy_reset(phy, true); | ||||||
| 
 |  | ||||||
| 		if (rc == 0) | 		if (rc == 0) | ||||||
| 			hisi_sas_release_task(hisi_hba, device); | 			hisi_sas_release_task(hisi_hba, device); | ||||||
| 		sas_put_local_phy(phy); | 		sas_put_local_phy(phy); | ||||||
|  | @ -2123,7 +2111,7 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy, | ||||||
| 		hisi_sas_bytes_dmaed(hisi_hba, phy_no, gfp_flags); | 		hisi_sas_bytes_dmaed(hisi_hba, phy_no, gfp_flags); | ||||||
| 		hisi_sas_port_notify_formed(sas_phy); | 		hisi_sas_port_notify_formed(sas_phy); | ||||||
| 	} else { | 	} else { | ||||||
| 		struct hisi_sas_port *port  = phy->port; | 		struct hisi_sas_port *port = phy->port; | ||||||
| 
 | 
 | ||||||
| 		if (test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) || | 		if (test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) || | ||||||
| 		    phy->in_reset) { | 		    phy->in_reset) { | ||||||
|  | @ -2296,12 +2284,14 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) | ||||||
| 		goto err_out; | 		goto err_out; | ||||||
| 
 | 
 | ||||||
| 	/* roundup to avoid overly large block size */ | 	/* roundup to avoid overly large block size */ | ||||||
| 	max_command_entries_ru = roundup(max_command_entries, 64); | 	max_command_entries_ru = roundup(max_command_entries, | ||||||
|  | 					 BLK_CNT_OPTIMIZE_MARK); | ||||||
| 	if (hisi_hba->prot_mask & HISI_SAS_DIX_PROT_MASK) | 	if (hisi_hba->prot_mask & HISI_SAS_DIX_PROT_MASK) | ||||||
| 		sz_slot_buf_ru = sizeof(struct hisi_sas_slot_dif_buf_table); | 		sz_slot_buf_ru = sizeof(struct hisi_sas_slot_dif_buf_table); | ||||||
| 	else | 	else | ||||||
| 		sz_slot_buf_ru = sizeof(struct hisi_sas_slot_buf_table); | 		sz_slot_buf_ru = sizeof(struct hisi_sas_slot_buf_table); | ||||||
| 	sz_slot_buf_ru = roundup(sz_slot_buf_ru, 64); | 
 | ||||||
|  | 	sz_slot_buf_ru = roundup(sz_slot_buf_ru, BLK_CNT_OPTIMIZE_MARK); | ||||||
| 	s = max(lcm(max_command_entries_ru, sz_slot_buf_ru), PAGE_SIZE); | 	s = max(lcm(max_command_entries_ru, sz_slot_buf_ru), PAGE_SIZE); | ||||||
| 	blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s; | 	blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s; | ||||||
| 	slots_per_blk = s / sz_slot_buf_ru; | 	slots_per_blk = s / sz_slot_buf_ru; | ||||||
|  | @ -2466,7 +2456,8 @@ int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba) | ||||||
| 	if (IS_ERR(refclk)) | 	if (IS_ERR(refclk)) | ||||||
| 		dev_dbg(dev, "no ref clk property\n"); | 		dev_dbg(dev, "no ref clk property\n"); | ||||||
| 	else | 	else | ||||||
| 		hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000; | 		hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / | ||||||
|  | 						 HZ_TO_MHZ; | ||||||
| 
 | 
 | ||||||
| 	if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) { | 	if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) { | ||||||
| 		dev_err(dev, "could not get property phy-count\n"); | 		dev_err(dev, "could not get property phy-count\n"); | ||||||
|  | @ -2588,7 +2579,7 @@ int hisi_sas_probe(struct platform_device *pdev, | ||||||
| 	shost->max_id = HISI_SAS_MAX_DEVICES; | 	shost->max_id = HISI_SAS_MAX_DEVICES; | ||||||
| 	shost->max_lun = ~0; | 	shost->max_lun = ~0; | ||||||
| 	shost->max_channel = 1; | 	shost->max_channel = 1; | ||||||
| 	shost->max_cmd_len = 16; | 	shost->max_cmd_len = HISI_SAS_MAX_CDB_LEN; | ||||||
| 	if (hisi_hba->hw->slot_index_alloc) { | 	if (hisi_hba->hw->slot_index_alloc) { | ||||||
| 		shost->can_queue = HISI_SAS_MAX_COMMANDS; | 		shost->can_queue = HISI_SAS_MAX_COMMANDS; | ||||||
| 		shost->cmd_per_lun = HISI_SAS_MAX_COMMANDS; | 		shost->cmd_per_lun = HISI_SAS_MAX_COMMANDS; | ||||||
|  |  | ||||||
|  | @ -1759,7 +1759,7 @@ static const struct scsi_host_template sht_v1_hw = { | ||||||
| 	.sg_tablesize		= HISI_SAS_SGE_PAGE_CNT, | 	.sg_tablesize		= HISI_SAS_SGE_PAGE_CNT, | ||||||
| 	.sdev_init		= hisi_sas_sdev_init, | 	.sdev_init		= hisi_sas_sdev_init, | ||||||
| 	.shost_groups		= host_v1_hw_groups, | 	.shost_groups		= host_v1_hw_groups, | ||||||
| 	.host_reset             = hisi_sas_host_reset, | 	.host_reset		= hisi_sas_host_reset, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct hisi_sas_hw hisi_sas_v1_hw = { | static const struct hisi_sas_hw hisi_sas_v1_hw = { | ||||||
|  |  | ||||||
|  | @ -2771,7 +2771,7 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p) | ||||||
| 	irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) | 	irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) | ||||||
| 		   >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff; | 		   >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff; | ||||||
| 	while (irq_msk) { | 	while (irq_msk) { | ||||||
| 		if (irq_msk  & 1) { | 		if (irq_msk & 1) { | ||||||
| 			u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, | 			u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, | ||||||
| 					    CHL_INT0); | 					    CHL_INT0); | ||||||
| 
 | 
 | ||||||
|  | @ -3111,7 +3111,7 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) | ||||||
| 	return IRQ_HANDLED; | 	return IRQ_HANDLED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static irqreturn_t  cq_thread_v2_hw(int irq_no, void *p) | static irqreturn_t cq_thread_v2_hw(int irq_no, void *p) | ||||||
| { | { | ||||||
| 	struct hisi_sas_cq *cq = p; | 	struct hisi_sas_cq *cq = p; | ||||||
| 	struct hisi_hba *hisi_hba = cq->hisi_hba; | 	struct hisi_hba *hisi_hba = cq->hisi_hba; | ||||||
|  | @ -3499,7 +3499,7 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, | ||||||
| 			 * numbered drive in the fourth byte. | 			 * numbered drive in the fourth byte. | ||||||
| 			 * See SFF-8485 Rev. 0.7 Table 24. | 			 * See SFF-8485 Rev. 0.7 Table 24. | ||||||
| 			 */ | 			 */ | ||||||
| 			void __iomem  *reg_addr = hisi_hba->sgpio_regs + | 			void __iomem *reg_addr = hisi_hba->sgpio_regs + | ||||||
| 					reg_index * 4 + phy_no; | 					reg_index * 4 + phy_no; | ||||||
| 			int data_idx = phy_no + 3 - (phy_no % 4) * 2; | 			int data_idx = phy_no + 3 - (phy_no % 4) * 2; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -466,6 +466,12 @@ | ||||||
| #define ITCT_HDR_RTOLT_OFF		48 | #define ITCT_HDR_RTOLT_OFF		48 | ||||||
| #define ITCT_HDR_RTOLT_MSK		(0xffffULL << ITCT_HDR_RTOLT_OFF) | #define ITCT_HDR_RTOLT_MSK		(0xffffULL << ITCT_HDR_RTOLT_OFF) | ||||||
| 
 | 
 | ||||||
|  | /*debugfs*/ | ||||||
|  | #define TWO_PARA_PER_LINE 2 | ||||||
|  | #define FOUR_PARA_PER_LINE 4 | ||||||
|  | #define	DUMP_BUF_SIZE 8 | ||||||
|  | #define BIST_BUF_SIZE 16 | ||||||
|  | 
 | ||||||
| struct hisi_sas_protect_iu_v3_hw { | struct hisi_sas_protect_iu_v3_hw { | ||||||
| 	u32 dw0; | 	u32 dw0; | ||||||
| 	u32 lbrtcv; | 	u32 lbrtcv; | ||||||
|  | @ -536,6 +542,43 @@ struct hisi_sas_err_record_v3 { | ||||||
| 
 | 
 | ||||||
| #define BASE_VECTORS_V3_HW  16 | #define BASE_VECTORS_V3_HW  16 | ||||||
| #define MIN_AFFINE_VECTORS_V3_HW  (BASE_VECTORS_V3_HW + 1) | #define MIN_AFFINE_VECTORS_V3_HW  (BASE_VECTORS_V3_HW + 1) | ||||||
|  | #define IRQ_PHY_UP_DOWN_INDEX 1 | ||||||
|  | #define IRQ_CHL_INDEX 2 | ||||||
|  | #define IRQ_AXI_INDEX 11 | ||||||
|  | 
 | ||||||
|  | #define DELAY_FOR_RESET_HW 100 | ||||||
|  | #define HDR_SG_MOD 0x2 | ||||||
|  | #define LUN_SIZE 8 | ||||||
|  | #define ATTR_PRIO_REGION 9 | ||||||
|  | #define CDB_REGION 12 | ||||||
|  | #define PRIO_OFF 3 | ||||||
|  | #define TMF_REGION 10 | ||||||
|  | #define TAG_MSB 12 | ||||||
|  | #define TAG_LSB 13 | ||||||
|  | #define SMP_FRAME_TYPE 2 | ||||||
|  | #define SMP_CRC_SIZE 4 | ||||||
|  | #define HDR_TAG_OFF 3 | ||||||
|  | #define HOST_NO_OFF 6 | ||||||
|  | #define PHY_NO_OFF 7 | ||||||
|  | #define IDENTIFY_REG_READ 6 | ||||||
|  | #define LINK_RESET_TIMEOUT_OFF 4 | ||||||
|  | #define DECIMALISM_FLAG 10 | ||||||
|  | #define WAIT_RETRY 100 | ||||||
|  | #define WAIT_TMROUT 5000 | ||||||
|  | 
 | ||||||
|  | #define ID_DWORD0_INDEX 0 | ||||||
|  | #define ID_DWORD1_INDEX 1 | ||||||
|  | #define ID_DWORD2_INDEX 2 | ||||||
|  | #define ID_DWORD3_INDEX 3 | ||||||
|  | #define ID_DWORD4_INDEX 4 | ||||||
|  | #define ID_DWORD5_INDEX 5 | ||||||
|  | #define TICKS_BIT_INDEX 24 | ||||||
|  | #define COUNT_BIT_INDEX 8 | ||||||
|  | 
 | ||||||
|  | #define PORT_REG_LENGTH	    0x100 | ||||||
|  | #define GLOBAL_REG_LENGTH   0x800 | ||||||
|  | #define	AXI_REG_LENGTH	    0x61 | ||||||
|  | #define RAS_REG_LENGTH	    0x10 | ||||||
| 
 | 
 | ||||||
| #define CHNL_INT_STS_MSK	0xeeeeeeee | #define CHNL_INT_STS_MSK	0xeeeeeeee | ||||||
| #define CHNL_INT_STS_PHY_MSK	0xe | #define CHNL_INT_STS_PHY_MSK	0xe | ||||||
|  | @ -811,17 +854,17 @@ static void config_id_frame_v3_hw(struct hisi_hba *hisi_hba, int phy_no) | ||||||
| 	identify_buffer = (u32 *)(&identify_frame); | 	identify_buffer = (u32 *)(&identify_frame); | ||||||
| 
 | 
 | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0, | 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0, | ||||||
| 			__swab32(identify_buffer[0])); | 			__swab32(identify_buffer[ID_DWORD0_INDEX])); | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1, | 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1, | ||||||
| 			__swab32(identify_buffer[1])); | 			__swab32(identify_buffer[ID_DWORD1_INDEX])); | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2, | 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2, | ||||||
| 			__swab32(identify_buffer[2])); | 			__swab32(identify_buffer[ID_DWORD2_INDEX])); | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3, | 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3, | ||||||
| 			__swab32(identify_buffer[3])); | 			__swab32(identify_buffer[ID_DWORD3_INDEX])); | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4, | 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4, | ||||||
| 			__swab32(identify_buffer[4])); | 			__swab32(identify_buffer[ID_DWORD4_INDEX])); | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5, | 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5, | ||||||
| 			__swab32(identify_buffer[5])); | 			__swab32(identify_buffer[ID_DWORD5_INDEX])); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, | static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, | ||||||
|  | @ -941,7 +984,7 @@ static int reset_hw_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 
 | 
 | ||||||
| 	/* Disable all of the PHYs */ | 	/* Disable all of the PHYs */ | ||||||
| 	hisi_sas_stop_phys(hisi_hba); | 	hisi_sas_stop_phys(hisi_hba); | ||||||
| 	udelay(50); | 	udelay(HISI_SAS_DELAY_FOR_PHY_DISABLE); | ||||||
| 
 | 
 | ||||||
| 	/* Ensure axi bus idle */ | 	/* Ensure axi bus idle */ | ||||||
| 	ret = hisi_sas_read32_poll_timeout(AXI_CFG, val, !val, | 	ret = hisi_sas_read32_poll_timeout(AXI_CFG, val, !val, | ||||||
|  | @ -981,7 +1024,7 @@ static int hw_init_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 		return rc; | 		return rc; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	msleep(100); | 	msleep(DELAY_FOR_RESET_HW); | ||||||
| 	init_reg_v3_hw(hisi_hba); | 	init_reg_v3_hw(hisi_hba); | ||||||
| 
 | 
 | ||||||
| 	if (guid_parse("D5918B4B-37AE-4E10-A99F-E5E8A6EF4C1F", &guid)) { | 	if (guid_parse("D5918B4B-37AE-4E10-A99F-E5E8A6EF4C1F", &guid)) { | ||||||
|  | @ -1030,7 +1073,7 @@ static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) | ||||||
| 	cfg &= ~PHY_CFG_ENA_MSK; | 	cfg &= ~PHY_CFG_ENA_MSK; | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); | 	hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); | ||||||
| 
 | 
 | ||||||
| 	mdelay(50); | 	mdelay(HISI_SAS_DELAY_FOR_PHY_DISABLE); | ||||||
| 
 | 
 | ||||||
| 	state = hisi_sas_read32(hisi_hba, PHY_STATE); | 	state = hisi_sas_read32(hisi_hba, PHY_STATE); | ||||||
| 	if (state & BIT(phy_no)) { | 	if (state & BIT(phy_no)) { | ||||||
|  | @ -1066,7 +1109,7 @@ static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no) | ||||||
| 		hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, | 		hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, | ||||||
| 					txid_auto | TX_HARDRST_MSK); | 					txid_auto | TX_HARDRST_MSK); | ||||||
| 	} | 	} | ||||||
| 	msleep(100); | 	msleep(HISI_SAS_DELAY_FOR_PHY_DISABLE); | ||||||
| 	hisi_sas_phy_enable(hisi_hba, phy_no, 1); | 	hisi_sas_phy_enable(hisi_hba, phy_no, 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1111,7 +1154,8 @@ static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id) | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < hisi_hba->n_phy; i++) | 	for (i = 0; i < hisi_hba->n_phy; i++) | ||||||
| 		if (phy_state & BIT(i)) | 		if (phy_state & BIT(i)) | ||||||
| 			if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id) | 			if (((phy_port_num_ma >> (i * HISI_SAS_REG_MEM_SIZE)) & 0xf) == | ||||||
|  | 			    port_id) | ||||||
| 				bitmap |= BIT(i); | 				bitmap |= BIT(i); | ||||||
| 
 | 
 | ||||||
| 	return bitmap; | 	return bitmap; | ||||||
|  | @ -1308,10 +1352,10 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 	/* map itct entry */ | 	/* map itct entry */ | ||||||
| 	dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; | 	dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; | ||||||
| 
 | 
 | ||||||
| 	dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr) | 	dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr) + | ||||||
| 	      + 3) / 4) << CMD_HDR_CFL_OFF) | | 	         3) / BYTE_TO_DW) << CMD_HDR_CFL_OFF) | | ||||||
| 	      ((HISI_SAS_MAX_SSP_RESP_SZ / 4) << CMD_HDR_MRFL_OFF) | | 	      ((HISI_SAS_MAX_SSP_RESP_SZ / BYTE_TO_DW) << CMD_HDR_MRFL_OFF) | | ||||||
| 	      (2 << CMD_HDR_SG_MOD_OFF); | 	      (HDR_SG_MOD << CMD_HDR_SG_MOD_OFF); | ||||||
| 	hdr->dw2 = cpu_to_le32(dw2); | 	hdr->dw2 = cpu_to_le32(dw2); | ||||||
| 	hdr->transfer_tags = cpu_to_le32(slot->idx); | 	hdr->transfer_tags = cpu_to_le32(slot->idx); | ||||||
| 
 | 
 | ||||||
|  | @ -1331,18 +1375,19 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 	buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot) + | 	buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot) + | ||||||
| 		sizeof(struct ssp_frame_hdr); | 		sizeof(struct ssp_frame_hdr); | ||||||
| 
 | 
 | ||||||
| 	memcpy(buf_cmd, &task->ssp_task.LUN, 8); | 	memcpy(buf_cmd, &task->ssp_task.LUN, LUN_SIZE); | ||||||
| 	if (!tmf) { | 	if (!tmf) { | ||||||
| 		buf_cmd[9] = ssp_task->task_attr; | 		buf_cmd[ATTR_PRIO_REGION] = ssp_task->task_attr; | ||||||
| 		memcpy(buf_cmd + 12, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); | 		memcpy(buf_cmd + CDB_REGION, scsi_cmnd->cmnd, | ||||||
|  | 		       scsi_cmnd->cmd_len); | ||||||
| 	} else { | 	} else { | ||||||
| 		buf_cmd[10] = tmf->tmf; | 		buf_cmd[TMF_REGION] = tmf->tmf; | ||||||
| 		switch (tmf->tmf) { | 		switch (tmf->tmf) { | ||||||
| 		case TMF_ABORT_TASK: | 		case TMF_ABORT_TASK: | ||||||
| 		case TMF_QUERY_TASK: | 		case TMF_QUERY_TASK: | ||||||
| 			buf_cmd[12] = | 			buf_cmd[TAG_MSB] = | ||||||
| 				(tmf->tag_of_task_to_be_managed >> 8) & 0xff; | 				(tmf->tag_of_task_to_be_managed >> 8) & 0xff; | ||||||
| 			buf_cmd[13] = | 			buf_cmd[TAG_LSB] = | ||||||
| 				tmf->tag_of_task_to_be_managed & 0xff; | 				tmf->tag_of_task_to_be_managed & 0xff; | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
|  | @ -1375,7 +1420,8 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 			unsigned int interval = scsi_prot_interval(scsi_cmnd); | 			unsigned int interval = scsi_prot_interval(scsi_cmnd); | ||||||
| 			unsigned int ilog2_interval = ilog2(interval); | 			unsigned int ilog2_interval = ilog2(interval); | ||||||
| 
 | 
 | ||||||
| 			len = (task->total_xfer_len >> ilog2_interval) * 8; | 			len = (task->total_xfer_len >> ilog2_interval) * | ||||||
|  | 			      BYTE_TO_DDW; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1395,6 +1441,7 @@ static void prep_smp_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 	struct hisi_sas_device *sas_dev = device->lldd_dev; | 	struct hisi_sas_device *sas_dev = device->lldd_dev; | ||||||
| 	dma_addr_t req_dma_addr; | 	dma_addr_t req_dma_addr; | ||||||
| 	unsigned int req_len; | 	unsigned int req_len; | ||||||
|  | 	u32 cfl; | ||||||
| 
 | 
 | ||||||
| 	/* req */ | 	/* req */ | ||||||
| 	sg_req = &task->smp_task.smp_req; | 	sg_req = &task->smp_task.smp_req; | ||||||
|  | @ -1405,7 +1452,7 @@ static void prep_smp_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 	/* dw0 */ | 	/* dw0 */ | ||||||
| 	hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) | | 	hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) | | ||||||
| 			       (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */ | 			       (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */ | ||||||
| 			       (2 << CMD_HDR_CMD_OFF)); /* smp */ | 			       (SMP_FRAME_TYPE << CMD_HDR_CMD_OFF)); /* smp */ | ||||||
| 
 | 
 | ||||||
| 	/* map itct entry */ | 	/* map itct entry */ | ||||||
| 	hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) | | 	hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) | | ||||||
|  | @ -1413,8 +1460,9 @@ static void prep_smp_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 			       (DIR_NO_DATA << CMD_HDR_DIR_OFF)); | 			       (DIR_NO_DATA << CMD_HDR_DIR_OFF)); | ||||||
| 
 | 
 | ||||||
| 	/* dw2 */ | 	/* dw2 */ | ||||||
| 	hdr->dw2 = cpu_to_le32((((req_len - 4) / 4) << CMD_HDR_CFL_OFF) | | 	cfl = (req_len - SMP_CRC_SIZE) / BYTE_TO_DW; | ||||||
| 			       (HISI_SAS_MAX_SMP_RESP_SZ / 4 << | 	hdr->dw2 = cpu_to_le32((cfl << CMD_HDR_CFL_OFF) | | ||||||
|  | 			       (HISI_SAS_MAX_SMP_RESP_SZ / BYTE_TO_DW << | ||||||
| 			       CMD_HDR_MRFL_OFF)); | 			       CMD_HDR_MRFL_OFF)); | ||||||
| 
 | 
 | ||||||
| 	hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF); | 	hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF); | ||||||
|  | @ -1479,12 +1527,13 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 		struct ata_queued_cmd *qc = task->uldd_task; | 		struct ata_queued_cmd *qc = task->uldd_task; | ||||||
| 
 | 
 | ||||||
| 		hdr_tag = qc->tag; | 		hdr_tag = qc->tag; | ||||||
| 		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); | 		task->ata_task.fis.sector_count |= | ||||||
|  | 				(u8)(hdr_tag << HDR_TAG_OFF); | ||||||
| 		dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; | 		dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF | | 	dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / BYTE_TO_DW) << CMD_HDR_CFL_OFF | | ||||||
| 			2 << CMD_HDR_SG_MOD_OFF; | 		HDR_SG_MOD << CMD_HDR_SG_MOD_OFF; | ||||||
| 	hdr->dw2 = cpu_to_le32(dw2); | 	hdr->dw2 = cpu_to_le32(dw2); | ||||||
| 
 | 
 | ||||||
| 	/* dw3 */ | 	/* dw3 */ | ||||||
|  | @ -1544,9 +1593,9 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); | 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); | ||||||
| 
 | 
 | ||||||
| 	port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); | 	port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); | ||||||
| 	port_id = (port_id >> (4 * phy_no)) & 0xf; | 	port_id = (port_id >> (HISI_SAS_REG_MEM_SIZE * phy_no)) & 0xf; | ||||||
| 	link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); | 	link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); | ||||||
| 	link_rate = (link_rate >> (phy_no * 4)) & 0xf; | 	link_rate = (link_rate >> (phy_no * HISI_SAS_REG_MEM_SIZE)) & 0xf; | ||||||
| 
 | 
 | ||||||
| 	if (port_id == 0xf) { | 	if (port_id == 0xf) { | ||||||
| 		dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); | 		dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); | ||||||
|  | @ -1579,8 +1628,8 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) | ||||||
| 
 | 
 | ||||||
| 		sas_phy->oob_mode = SATA_OOB_MODE; | 		sas_phy->oob_mode = SATA_OOB_MODE; | ||||||
| 		attached_sas_addr[0] = 0x50; | 		attached_sas_addr[0] = 0x50; | ||||||
| 		attached_sas_addr[6] = shost->host_no; | 		attached_sas_addr[HOST_NO_OFF] = shost->host_no; | ||||||
| 		attached_sas_addr[7] = phy_no; | 		attached_sas_addr[PHY_NO_OFF] = phy_no; | ||||||
| 		memcpy(sas_phy->attached_sas_addr, | 		memcpy(sas_phy->attached_sas_addr, | ||||||
| 		       attached_sas_addr, | 		       attached_sas_addr, | ||||||
| 		       SAS_ADDR_SIZE); | 		       SAS_ADDR_SIZE); | ||||||
|  | @ -1596,7 +1645,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) | ||||||
| 			(struct sas_identify_frame *)frame_rcvd; | 			(struct sas_identify_frame *)frame_rcvd; | ||||||
| 
 | 
 | ||||||
| 		dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); | 		dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); | ||||||
| 		for (i = 0; i < 6; i++) { | 		for (i = 0; i < IDENTIFY_REG_READ; i++) { | ||||||
| 			u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no, | 			u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no, | ||||||
| 					       RX_IDAF_DWORD0 + (i * 4)); | 					       RX_IDAF_DWORD0 + (i * 4)); | ||||||
| 			frame_rcvd[i] = __swab32(idaf); | 			frame_rcvd[i] = __swab32(idaf); | ||||||
|  | @ -1701,7 +1750,7 @@ static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p) | ||||||
| 	irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) | 	irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) | ||||||
| 				& 0x11111111; | 				& 0x11111111; | ||||||
| 	while (irq_msk) { | 	while (irq_msk) { | ||||||
| 		if (irq_msk  & 1) { | 		if (irq_msk & 1) { | ||||||
| 			u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, | 			u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, | ||||||
| 							    CHL_INT0); | 							    CHL_INT0); | ||||||
| 			u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); | 			u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); | ||||||
|  | @ -1866,7 +1915,7 @@ static void handle_chl_int2_v3_hw(struct hisi_hba *hisi_hba, int phy_no) | ||||||
| 
 | 
 | ||||||
| 		dev_warn(dev, "phy%d stp link timeout (0x%x)\n", | 		dev_warn(dev, "phy%d stp link timeout (0x%x)\n", | ||||||
| 			 phy_no, reg_value); | 			 phy_no, reg_value); | ||||||
| 		if (reg_value & BIT(4)) | 		if (reg_value & BIT(LINK_RESET_TIMEOUT_OFF)) | ||||||
| 			hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); | 			hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1924,8 +1973,7 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) | ||||||
| 	u32 irq_msk; | 	u32 irq_msk; | ||||||
| 	int phy_no = 0; | 	int phy_no = 0; | ||||||
| 
 | 
 | ||||||
| 	irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) | 	irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) & CHNL_INT_STS_MSK; | ||||||
| 		  & CHNL_INT_STS_MSK; |  | ||||||
| 
 | 
 | ||||||
| 	while (irq_msk) { | 	while (irq_msk) { | ||||||
| 		if (irq_msk & (CHNL_INT_STS_INT0_MSK << (phy_no * CHNL_WIDTH))) | 		if (irq_msk & (CHNL_INT_STS_INT0_MSK << (phy_no * CHNL_WIDTH))) | ||||||
|  | @ -2570,7 +2618,6 @@ static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	if (vectors < 0) | 	if (vectors < 0) | ||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW - hisi_hba->iopoll_q_cnt; | 	hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW - hisi_hba->iopoll_q_cnt; | ||||||
| 	shost->nr_hw_queues = hisi_hba->cq_nvecs + hisi_hba->iopoll_q_cnt; | 	shost->nr_hw_queues = hisi_hba->cq_nvecs + hisi_hba->iopoll_q_cnt; | ||||||
| 
 | 
 | ||||||
|  | @ -2583,7 +2630,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	struct pci_dev *pdev = hisi_hba->pci_dev; | 	struct pci_dev *pdev = hisi_hba->pci_dev; | ||||||
| 	int rc, i; | 	int rc, i; | ||||||
| 
 | 
 | ||||||
| 	rc = devm_request_irq(dev, pci_irq_vector(pdev, 1), | 	rc = devm_request_irq(dev, pci_irq_vector(pdev, IRQ_PHY_UP_DOWN_INDEX), | ||||||
| 			      int_phy_up_down_bcast_v3_hw, 0, | 			      int_phy_up_down_bcast_v3_hw, 0, | ||||||
| 			      DRV_NAME " phy", hisi_hba); | 			      DRV_NAME " phy", hisi_hba); | ||||||
| 	if (rc) { | 	if (rc) { | ||||||
|  | @ -2591,7 +2638,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rc = devm_request_irq(dev, pci_irq_vector(pdev, 2), | 	rc = devm_request_irq(dev, pci_irq_vector(pdev, IRQ_CHL_INDEX), | ||||||
| 			      int_chnl_int_v3_hw, 0, | 			      int_chnl_int_v3_hw, 0, | ||||||
| 			      DRV_NAME " channel", hisi_hba); | 			      DRV_NAME " channel", hisi_hba); | ||||||
| 	if (rc) { | 	if (rc) { | ||||||
|  | @ -2599,7 +2646,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rc = devm_request_irq(dev, pci_irq_vector(pdev, 11), | 	rc = devm_request_irq(dev, pci_irq_vector(pdev, IRQ_AXI_INDEX), | ||||||
| 			      fatal_axi_int_v3_hw, 0, | 			      fatal_axi_int_v3_hw, 0, | ||||||
| 			      DRV_NAME " fatal", hisi_hba); | 			      DRV_NAME " fatal", hisi_hba); | ||||||
| 	if (rc) { | 	if (rc) { | ||||||
|  | @ -2612,7 +2659,8 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < hisi_hba->cq_nvecs; i++) { | 	for (i = 0; i < hisi_hba->cq_nvecs; i++) { | ||||||
| 		struct hisi_sas_cq *cq = &hisi_hba->cq[i]; | 		struct hisi_sas_cq *cq = &hisi_hba->cq[i]; | ||||||
| 		int nr = hisi_sas_intr_conv ? 16 : 16 + i; | 		int nr = hisi_sas_intr_conv ? BASE_VECTORS_V3_HW : | ||||||
|  | 					      BASE_VECTORS_V3_HW + i; | ||||||
| 		unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : | 		unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : | ||||||
| 							      IRQF_ONESHOT; | 							      IRQF_ONESHOT; | ||||||
| 
 | 
 | ||||||
|  | @ -2670,14 +2718,14 @@ static void interrupt_disable_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	struct pci_dev *pdev = hisi_hba->pci_dev; | 	struct pci_dev *pdev = hisi_hba->pci_dev; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	synchronize_irq(pci_irq_vector(pdev, 1)); | 	synchronize_irq(pci_irq_vector(pdev, IRQ_PHY_UP_DOWN_INDEX)); | ||||||
| 	synchronize_irq(pci_irq_vector(pdev, 2)); | 	synchronize_irq(pci_irq_vector(pdev, IRQ_CHL_INDEX)); | ||||||
| 	synchronize_irq(pci_irq_vector(pdev, 11)); | 	synchronize_irq(pci_irq_vector(pdev, IRQ_AXI_INDEX)); | ||||||
| 	for (i = 0; i < hisi_hba->queue_count; i++) | 	for (i = 0; i < hisi_hba->queue_count; i++) | ||||||
| 		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1); | 		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < hisi_hba->cq_nvecs; i++) | 	for (i = 0; i < hisi_hba->cq_nvecs; i++) | ||||||
| 		synchronize_irq(pci_irq_vector(pdev, i + 16)); | 		synchronize_irq(pci_irq_vector(pdev, i + BASE_VECTORS_V3_HW)); | ||||||
| 
 | 
 | ||||||
| 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff); | 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff); | ||||||
| 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff); | 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff); | ||||||
|  | @ -2709,7 +2757,7 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 
 | 
 | ||||||
| 	hisi_sas_stop_phys(hisi_hba); | 	hisi_sas_stop_phys(hisi_hba); | ||||||
| 
 | 
 | ||||||
| 	mdelay(10); | 	mdelay(HISI_SAS_DELAY_FOR_PHY_DISABLE); | ||||||
| 
 | 
 | ||||||
| 	reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE + | 	reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE + | ||||||
| 				  AM_CTRL_GLOBAL); | 				  AM_CTRL_GLOBAL); | ||||||
|  | @ -2846,13 +2894,13 @@ static ssize_t intr_coal_ticks_v3_hw_store(struct device *dev, | ||||||
| 	u32 intr_coal_ticks; | 	u32 intr_coal_ticks; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	ret = kstrtou32(buf, 10, &intr_coal_ticks); | 	ret = kstrtou32(buf, DECIMALISM_FLAG, &intr_coal_ticks); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		dev_err(dev, "Input data of interrupt coalesce unmatch\n"); | 		dev_err(dev, "Input data of interrupt coalesce unmatch\n"); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (intr_coal_ticks >= BIT(24)) { | 	if (intr_coal_ticks >= BIT(TICKS_BIT_INDEX)) { | ||||||
| 		dev_err(dev, "intr_coal_ticks must be less than 2^24!\n"); | 		dev_err(dev, "intr_coal_ticks must be less than 2^24!\n"); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
|  | @ -2885,13 +2933,13 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev, | ||||||
| 	u32 intr_coal_count; | 	u32 intr_coal_count; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	ret = kstrtou32(buf, 10, &intr_coal_count); | 	ret = kstrtou32(buf, DECIMALISM_FLAG, &intr_coal_count); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		dev_err(dev, "Input data of interrupt coalesce unmatch\n"); | 		dev_err(dev, "Input data of interrupt coalesce unmatch\n"); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (intr_coal_count >= BIT(8)) { | 	if (intr_coal_count >= BIT(COUNT_BIT_INDEX)) { | ||||||
| 		dev_err(dev, "intr_coal_count must be less than 2^8!\n"); | 		dev_err(dev, "intr_coal_count must be less than 2^8!\n"); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
|  | @ -3023,7 +3071,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_port_reg_lu[] = { | ||||||
| 
 | 
 | ||||||
| static const struct hisi_sas_debugfs_reg debugfs_port_reg = { | static const struct hisi_sas_debugfs_reg debugfs_port_reg = { | ||||||
| 	.lu = debugfs_port_reg_lu, | 	.lu = debugfs_port_reg_lu, | ||||||
| 	.count = 0x100, | 	.count = PORT_REG_LENGTH, | ||||||
| 	.base_off = PORT_BASE, | 	.base_off = PORT_BASE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -3097,7 +3145,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = { | ||||||
| 
 | 
 | ||||||
| static const struct hisi_sas_debugfs_reg debugfs_global_reg = { | static const struct hisi_sas_debugfs_reg debugfs_global_reg = { | ||||||
| 	.lu = debugfs_global_reg_lu, | 	.lu = debugfs_global_reg_lu, | ||||||
| 	.count = 0x800, | 	.count = GLOBAL_REG_LENGTH, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = { | static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = { | ||||||
|  | @ -3110,7 +3158,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = { | ||||||
| 
 | 
 | ||||||
| static const struct hisi_sas_debugfs_reg debugfs_axi_reg = { | static const struct hisi_sas_debugfs_reg debugfs_axi_reg = { | ||||||
| 	.lu = debugfs_axi_reg_lu, | 	.lu = debugfs_axi_reg_lu, | ||||||
| 	.count = 0x61, | 	.count = AXI_REG_LENGTH, | ||||||
| 	.base_off = AXI_MASTER_CFG_BASE, | 	.base_off = AXI_MASTER_CFG_BASE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -3127,7 +3175,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_ras_reg_lu[] = { | ||||||
| 
 | 
 | ||||||
| static const struct hisi_sas_debugfs_reg debugfs_ras_reg = { | static const struct hisi_sas_debugfs_reg debugfs_ras_reg = { | ||||||
| 	.lu = debugfs_ras_reg_lu, | 	.lu = debugfs_ras_reg_lu, | ||||||
| 	.count = 0x10, | 	.count = RAS_REG_LENGTH, | ||||||
| 	.base_off = RAS_BASE, | 	.base_off = RAS_BASE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -3136,7 +3184,7 @@ static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	struct Scsi_Host *shost = hisi_hba->shost; | 	struct Scsi_Host *shost = hisi_hba->shost; | ||||||
| 
 | 
 | ||||||
| 	scsi_block_requests(shost); | 	scsi_block_requests(shost); | ||||||
| 	wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000); | 	wait_cmds_complete_timeout_v3_hw(hisi_hba, WAIT_RETRY, WAIT_TMROUT); | ||||||
| 
 | 
 | ||||||
| 	set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); | 	set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); | ||||||
| 	hisi_sas_sync_cqs(hisi_hba); | 	hisi_sas_sync_cqs(hisi_hba); | ||||||
|  | @ -3177,7 +3225,7 @@ static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba, | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	memset(buf, 0, cache_dw_size * 4); | 	memset(buf, 0, cache_dw_size * BYTE_TO_DW); | ||||||
| 	buf[0] = val; | 	buf[0] = val; | ||||||
| 
 | 
 | ||||||
| 	for (i = 1; i < cache_dw_size; i++) | 	for (i = 1; i < cache_dw_size; i++) | ||||||
|  | @ -3224,7 +3272,7 @@ static void hisi_sas_bist_test_restore_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE); | 	reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE); | ||||||
| 	/* init OOB link rate as 1.5 Gbits */ | 	/* init OOB link rate as 1.5 Gbits */ | ||||||
| 	reg_val &= ~CFG_PROG_OOB_PHY_LINK_RATE_MSK; | 	reg_val &= ~CFG_PROG_OOB_PHY_LINK_RATE_MSK; | ||||||
| 	reg_val |= (0x8 << CFG_PROG_OOB_PHY_LINK_RATE_OFF); | 	reg_val |= (SAS_LINK_RATE_1_5_GBPS << CFG_PROG_OOB_PHY_LINK_RATE_OFF); | ||||||
| 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE, reg_val); | 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE, reg_val); | ||||||
| 
 | 
 | ||||||
| 	/* enable PHY */ | 	/* enable PHY */ | ||||||
|  | @ -3233,6 +3281,9 @@ static void hisi_sas_bist_test_restore_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 
 | 
 | ||||||
| #define SAS_PHY_BIST_CODE_INIT	0x1 | #define SAS_PHY_BIST_CODE_INIT	0x1 | ||||||
| #define SAS_PHY_BIST_CODE1_INIT	0X80 | #define SAS_PHY_BIST_CODE1_INIT	0X80 | ||||||
|  | #define SAS_PHY_BIST_INIT_DELAY 100 | ||||||
|  | #define SAS_PHY_BIST_LOOP_TEST_0 1 | ||||||
|  | #define SAS_PHY_BIST_LOOP_TEST_1 2 | ||||||
| static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) | static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) | ||||||
| { | { | ||||||
| 	u32 reg_val, mode_tmp; | 	u32 reg_val, mode_tmp; | ||||||
|  | @ -3251,12 +3302,13 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) | ||||||
| 		 ffe[FFE_SATA_1_5_GBPS], ffe[FFE_SATA_3_0_GBPS], | 		 ffe[FFE_SATA_1_5_GBPS], ffe[FFE_SATA_3_0_GBPS], | ||||||
| 		 ffe[FFE_SATA_6_0_GBPS], fix_code[FIXED_CODE], | 		 ffe[FFE_SATA_6_0_GBPS], fix_code[FIXED_CODE], | ||||||
| 		 fix_code[FIXED_CODE_1]); | 		 fix_code[FIXED_CODE_1]); | ||||||
| 	mode_tmp = path_mode ? 2 : 1; | 	mode_tmp = path_mode ? SAS_PHY_BIST_LOOP_TEST_1 : | ||||||
|  | 			       SAS_PHY_BIST_LOOP_TEST_0; | ||||||
| 	if (enable) { | 	if (enable) { | ||||||
| 		/* some preparations before bist test */ | 		/* some preparations before bist test */ | ||||||
| 		hisi_sas_bist_test_prep_v3_hw(hisi_hba); | 		hisi_sas_bist_test_prep_v3_hw(hisi_hba); | ||||||
| 
 | 
 | ||||||
| 		/* set linkrate of bit test*/ | 		/* set linkrate of bit test */ | ||||||
| 		reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, | 		reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, | ||||||
| 					      PROG_PHY_LINK_RATE); | 					      PROG_PHY_LINK_RATE); | ||||||
| 		reg_val &= ~CFG_PROG_OOB_PHY_LINK_RATE_MSK; | 		reg_val &= ~CFG_PROG_OOB_PHY_LINK_RATE_MSK; | ||||||
|  | @ -3294,13 +3346,13 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) | ||||||
| 					     SAS_PHY_BIST_CODE1_INIT); | 					     SAS_PHY_BIST_CODE1_INIT); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		mdelay(100); | 		mdelay(SAS_PHY_BIST_INIT_DELAY); | ||||||
| 		reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK); | 		reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK); | ||||||
| 		hisi_sas_phy_write32(hisi_hba, phy_no, SAS_PHY_BIST_CTRL, | 		hisi_sas_phy_write32(hisi_hba, phy_no, SAS_PHY_BIST_CTRL, | ||||||
| 				     reg_val); | 				     reg_val); | ||||||
| 
 | 
 | ||||||
| 		/* clear error bit */ | 		/* clear error bit */ | ||||||
| 		mdelay(100); | 		mdelay(SAS_PHY_BIST_INIT_DELAY); | ||||||
| 		hisi_sas_phy_read32(hisi_hba, phy_no, SAS_BIST_ERR_CNT); | 		hisi_sas_phy_read32(hisi_hba, phy_no, SAS_BIST_ERR_CNT); | ||||||
| 	} else { | 	} else { | ||||||
| 		/* disable bist test and recover it */ | 		/* disable bist test and recover it */ | ||||||
|  | @ -3354,7 +3406,7 @@ static const struct scsi_host_template sht_v3_hw = { | ||||||
| 	.shost_groups		= host_v3_hw_groups, | 	.shost_groups		= host_v3_hw_groups, | ||||||
| 	.sdev_groups		= sdev_groups_v3_hw, | 	.sdev_groups		= sdev_groups_v3_hw, | ||||||
| 	.tag_alloc_policy_rr	= true, | 	.tag_alloc_policy_rr	= true, | ||||||
| 	.host_reset             = hisi_sas_host_reset, | 	.host_reset		= hisi_sas_host_reset, | ||||||
| 	.host_tagset		= 1, | 	.host_tagset		= 1, | ||||||
| 	.mq_poll		= queue_complete_v3_hw, | 	.mq_poll		= queue_complete_v3_hw, | ||||||
| }; | }; | ||||||
|  | @ -3496,7 +3548,7 @@ static void debugfs_snapshot_port_reg_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { | 	for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { | ||||||
| 		databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data; | 		databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data; | ||||||
| 		for (i = 0; i < port->count; i++, databuf++) { | 		for (i = 0; i < port->count; i++, databuf++) { | ||||||
| 			offset = port->base_off + 4 * i; | 			offset = port->base_off + HISI_SAS_REG_MEM_SIZE * i; | ||||||
| 			*databuf = hisi_sas_phy_read32(hisi_hba, phy_cnt, | 			*databuf = hisi_sas_phy_read32(hisi_hba, phy_cnt, | ||||||
| 						       offset); | 						       offset); | ||||||
| 		} | 		} | ||||||
|  | @ -3510,7 +3562,8 @@ static void debugfs_snapshot_global_reg_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < debugfs_global_reg.count; i++, databuf++) | 	for (i = 0; i < debugfs_global_reg.count; i++, databuf++) | ||||||
| 		*databuf = hisi_sas_read32(hisi_hba, 4 * i); | 		*databuf = hisi_sas_read32(hisi_hba, | ||||||
|  | 					   HISI_SAS_REG_MEM_SIZE * i); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba) | static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba) | ||||||
|  | @ -3521,7 +3574,9 @@ static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < axi->count; i++, databuf++) | 	for (i = 0; i < axi->count; i++, databuf++) | ||||||
| 		*databuf = hisi_sas_read32(hisi_hba, 4 * i + axi->base_off); | 		*databuf = hisi_sas_read32(hisi_hba, | ||||||
|  | 					   HISI_SAS_REG_MEM_SIZE * i + | ||||||
|  | 					   axi->base_off); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba) | static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba) | ||||||
|  | @ -3532,7 +3587,9 @@ static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ras->count; i++, databuf++) | 	for (i = 0; i < ras->count; i++, databuf++) | ||||||
| 		*databuf = hisi_sas_read32(hisi_hba, 4 * i + ras->base_off); | 		*databuf = hisi_sas_read32(hisi_hba, | ||||||
|  | 					   HISI_SAS_REG_MEM_SIZE * i + | ||||||
|  | 					   ras->base_off); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void debugfs_snapshot_itct_reg_v3_hw(struct hisi_hba *hisi_hba) | static void debugfs_snapshot_itct_reg_v3_hw(struct hisi_hba *hisi_hba) | ||||||
|  | @ -3595,12 +3652,11 @@ static void debugfs_print_reg_v3_hw(u32 *regs_val, struct seq_file *s, | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < reg->count; i++) { | 	for (i = 0; i < reg->count; i++) { | ||||||
| 		int off = i * 4; | 		int off = i * HISI_SAS_REG_MEM_SIZE; | ||||||
| 		const char *name; | 		const char *name; | ||||||
| 
 | 
 | ||||||
| 		name = debugfs_to_reg_name_v3_hw(off, reg->base_off, | 		name = debugfs_to_reg_name_v3_hw(off, reg->base_off, | ||||||
| 						 reg->lu); | 						 reg->lu); | ||||||
| 
 |  | ||||||
| 		if (name) | 		if (name) | ||||||
| 			seq_printf(s, "0x%08x 0x%08x %s\n", off, | 			seq_printf(s, "0x%08x 0x%08x %s\n", off, | ||||||
| 				   regs_val[i], name); | 				   regs_val[i], name); | ||||||
|  | @ -3673,9 +3729,9 @@ static void debugfs_show_row_64_v3_hw(struct seq_file *s, int index, | ||||||
| 
 | 
 | ||||||
| 	/* completion header size not fixed per HW version */ | 	/* completion header size not fixed per HW version */ | ||||||
| 	seq_printf(s, "index %04d:\n\t", index); | 	seq_printf(s, "index %04d:\n\t", index); | ||||||
| 	for (i = 1; i <= sz / 8; i++, ptr++) { | 	for (i = 1; i <= sz / BYTE_TO_DDW; i++, ptr++) { | ||||||
| 		seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr)); | 		seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr)); | ||||||
| 		if (!(i % 2)) | 		if (!(i % TWO_PARA_PER_LINE)) | ||||||
| 			seq_puts(s, "\n\t"); | 			seq_puts(s, "\n\t"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -3689,9 +3745,9 @@ static void debugfs_show_row_32_v3_hw(struct seq_file *s, int index, | ||||||
| 
 | 
 | ||||||
| 	/* completion header size not fixed per HW version */ | 	/* completion header size not fixed per HW version */ | ||||||
| 	seq_printf(s, "index %04d:\n\t", index); | 	seq_printf(s, "index %04d:\n\t", index); | ||||||
| 	for (i = 1; i <= sz / 4; i++, ptr++) { | 	for (i = 1; i <= sz / BYTE_TO_DW; i++, ptr++) { | ||||||
| 		seq_printf(s, " 0x%08x", le32_to_cpu(*ptr)); | 		seq_printf(s, " 0x%08x", le32_to_cpu(*ptr)); | ||||||
| 		if (!(i % 4)) | 		if (!(i % FOUR_PARA_PER_LINE)) | ||||||
| 			seq_puts(s, "\n\t"); | 			seq_puts(s, "\n\t"); | ||||||
| 	} | 	} | ||||||
| 	seq_puts(s, "\n"); | 	seq_puts(s, "\n"); | ||||||
|  | @ -3776,7 +3832,7 @@ static int debugfs_iost_cache_v3_hw_show(struct seq_file *s, void *p) | ||||||
| 	struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private; | 	struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private; | ||||||
| 	struct hisi_sas_iost_itct_cache *iost_cache = | 	struct hisi_sas_iost_itct_cache *iost_cache = | ||||||
| 						debugfs_iost_cache->cache; | 						debugfs_iost_cache->cache; | ||||||
| 	u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; | 	u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * BYTE_TO_DW; | ||||||
| 	int i, tab_idx; | 	int i, tab_idx; | ||||||
| 	__le64 *iost; | 	__le64 *iost; | ||||||
| 
 | 
 | ||||||
|  | @ -3824,7 +3880,7 @@ static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p) | ||||||
| 	struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private; | 	struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private; | ||||||
| 	struct hisi_sas_iost_itct_cache *itct_cache = | 	struct hisi_sas_iost_itct_cache *itct_cache = | ||||||
| 						debugfs_itct_cache->cache; | 						debugfs_itct_cache->cache; | ||||||
| 	u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; | 	u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * BYTE_TO_DW; | ||||||
| 	int i, tab_idx; | 	int i, tab_idx; | ||||||
| 	__le64 *itct; | 	__le64 *itct; | ||||||
| 
 | 
 | ||||||
|  | @ -3853,12 +3909,12 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) | ||||||
| 	u64 *debugfs_timestamp; | 	u64 *debugfs_timestamp; | ||||||
| 	struct dentry *dump_dentry; | 	struct dentry *dump_dentry; | ||||||
| 	struct dentry *dentry; | 	struct dentry *dentry; | ||||||
| 	char name[256]; | 	char name[NAME_BUF_SIZE]; | ||||||
| 	int p; | 	int p; | ||||||
| 	int c; | 	int c; | ||||||
| 	int d; | 	int d; | ||||||
| 
 | 
 | ||||||
| 	snprintf(name, 256, "%d", index); | 	snprintf(name, NAME_BUF_SIZE, "%d", index); | ||||||
| 
 | 
 | ||||||
| 	dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); | 	dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); | ||||||
| 
 | 
 | ||||||
|  | @ -3874,7 +3930,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) | ||||||
| 	/* Create port dir and files */ | 	/* Create port dir and files */ | ||||||
| 	dentry = debugfs_create_dir("port", dump_dentry); | 	dentry = debugfs_create_dir("port", dump_dentry); | ||||||
| 	for (p = 0; p < hisi_hba->n_phy; p++) { | 	for (p = 0; p < hisi_hba->n_phy; p++) { | ||||||
| 		snprintf(name, 256, "%d", p); | 		snprintf(name, NAME_BUF_SIZE, "%d", p); | ||||||
| 
 | 
 | ||||||
| 		debugfs_create_file(name, 0400, dentry, | 		debugfs_create_file(name, 0400, dentry, | ||||||
| 				    &hisi_hba->debugfs_port_reg[index][p], | 				    &hisi_hba->debugfs_port_reg[index][p], | ||||||
|  | @ -3884,7 +3940,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) | ||||||
| 	/* Create CQ dir and files */ | 	/* Create CQ dir and files */ | ||||||
| 	dentry = debugfs_create_dir("cq", dump_dentry); | 	dentry = debugfs_create_dir("cq", dump_dentry); | ||||||
| 	for (c = 0; c < hisi_hba->queue_count; c++) { | 	for (c = 0; c < hisi_hba->queue_count; c++) { | ||||||
| 		snprintf(name, 256, "%d", c); | 		snprintf(name, NAME_BUF_SIZE, "%d", c); | ||||||
| 
 | 
 | ||||||
| 		debugfs_create_file(name, 0400, dentry, | 		debugfs_create_file(name, 0400, dentry, | ||||||
| 				    &hisi_hba->debugfs_cq[index][c], | 				    &hisi_hba->debugfs_cq[index][c], | ||||||
|  | @ -3894,7 +3950,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) | ||||||
| 	/* Create DQ dir and files */ | 	/* Create DQ dir and files */ | ||||||
| 	dentry = debugfs_create_dir("dq", dump_dentry); | 	dentry = debugfs_create_dir("dq", dump_dentry); | ||||||
| 	for (d = 0; d < hisi_hba->queue_count; d++) { | 	for (d = 0; d < hisi_hba->queue_count; d++) { | ||||||
| 		snprintf(name, 256, "%d", d); | 		snprintf(name, NAME_BUF_SIZE, "%d", d); | ||||||
| 
 | 
 | ||||||
| 		debugfs_create_file(name, 0400, dentry, | 		debugfs_create_file(name, 0400, dentry, | ||||||
| 				    &hisi_hba->debugfs_dq[index][d], | 				    &hisi_hba->debugfs_dq[index][d], | ||||||
|  | @ -3931,9 +3987,9 @@ static ssize_t debugfs_trigger_dump_v3_hw_write(struct file *file, | ||||||
| 						size_t count, loff_t *ppos) | 						size_t count, loff_t *ppos) | ||||||
| { | { | ||||||
| 	struct hisi_hba *hisi_hba = file->f_inode->i_private; | 	struct hisi_hba *hisi_hba = file->f_inode->i_private; | ||||||
| 	char buf[8]; | 	char buf[DUMP_BUF_SIZE]; | ||||||
| 
 | 
 | ||||||
| 	if (count > 8) | 	if (count > DUMP_BUF_SIZE) | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
| 
 | 
 | ||||||
| 	if (copy_from_user(buf, user_buf, count)) | 	if (copy_from_user(buf, user_buf, count)) | ||||||
|  | @ -3997,7 +4053,7 @@ static ssize_t debugfs_bist_linkrate_v3_hw_write(struct file *filp, | ||||||
| { | { | ||||||
| 	struct seq_file *m = filp->private_data; | 	struct seq_file *m = filp->private_data; | ||||||
| 	struct hisi_hba *hisi_hba = m->private; | 	struct hisi_hba *hisi_hba = m->private; | ||||||
| 	char kbuf[16] = {}, *pkbuf; | 	char kbuf[BIST_BUF_SIZE] = {}, *pkbuf; | ||||||
| 	bool found = false; | 	bool found = false; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
|  | @ -4014,7 +4070,7 @@ static ssize_t debugfs_bist_linkrate_v3_hw_write(struct file *filp, | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) { | 	for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) { | ||||||
| 		if (!strncmp(debugfs_loop_linkrate_v3_hw[i].name, | 		if (!strncmp(debugfs_loop_linkrate_v3_hw[i].name, | ||||||
| 			     pkbuf, 16)) { | 			     pkbuf, BIST_BUF_SIZE)) { | ||||||
| 			hisi_hba->debugfs_bist_linkrate = | 			hisi_hba->debugfs_bist_linkrate = | ||||||
| 				debugfs_loop_linkrate_v3_hw[i].value; | 				debugfs_loop_linkrate_v3_hw[i].value; | ||||||
| 			found = true; | 			found = true; | ||||||
|  | @ -4072,7 +4128,7 @@ static ssize_t debugfs_bist_code_mode_v3_hw_write(struct file *filp, | ||||||
| { | { | ||||||
| 	struct seq_file *m = filp->private_data; | 	struct seq_file *m = filp->private_data; | ||||||
| 	struct hisi_hba *hisi_hba = m->private; | 	struct hisi_hba *hisi_hba = m->private; | ||||||
| 	char kbuf[16] = {}, *pkbuf; | 	char kbuf[BIST_BUF_SIZE] = {}, *pkbuf; | ||||||
| 	bool found = false; | 	bool found = false; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
|  | @ -4089,7 +4145,7 @@ static ssize_t debugfs_bist_code_mode_v3_hw_write(struct file *filp, | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) { | 	for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) { | ||||||
| 		if (!strncmp(debugfs_loop_code_mode_v3_hw[i].name, | 		if (!strncmp(debugfs_loop_code_mode_v3_hw[i].name, | ||||||
| 			     pkbuf, 16)) { | 			     pkbuf, BIST_BUF_SIZE)) { | ||||||
| 			hisi_hba->debugfs_bist_code_mode = | 			hisi_hba->debugfs_bist_code_mode = | ||||||
| 				debugfs_loop_code_mode_v3_hw[i].value; | 				debugfs_loop_code_mode_v3_hw[i].value; | ||||||
| 			found = true; | 			found = true; | ||||||
|  | @ -4204,7 +4260,7 @@ static ssize_t debugfs_bist_mode_v3_hw_write(struct file *filp, | ||||||
| { | { | ||||||
| 	struct seq_file *m = filp->private_data; | 	struct seq_file *m = filp->private_data; | ||||||
| 	struct hisi_hba *hisi_hba = m->private; | 	struct hisi_hba *hisi_hba = m->private; | ||||||
| 	char kbuf[16] = {}, *pkbuf; | 	char kbuf[BIST_BUF_SIZE] = {}, *pkbuf; | ||||||
| 	bool found = false; | 	bool found = false; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
|  | @ -4220,7 +4276,8 @@ static ssize_t debugfs_bist_mode_v3_hw_write(struct file *filp, | ||||||
| 	pkbuf = strstrip(kbuf); | 	pkbuf = strstrip(kbuf); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) { | 	for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) { | ||||||
| 		if (!strncmp(debugfs_loop_modes_v3_hw[i].name, pkbuf, 16)) { | 		if (!strncmp(debugfs_loop_modes_v3_hw[i].name, pkbuf, | ||||||
|  | 			     BIST_BUF_SIZE)) { | ||||||
| 			hisi_hba->debugfs_bist_mode = | 			hisi_hba->debugfs_bist_mode = | ||||||
| 				debugfs_loop_modes_v3_hw[i].value; | 				debugfs_loop_modes_v3_hw[i].value; | ||||||
| 			found = true; | 			found = true; | ||||||
|  | @ -4499,8 +4556,9 @@ static int debugfs_fifo_data_v3_hw_show(struct seq_file *s, void *p) | ||||||
| 
 | 
 | ||||||
| 	debugfs_read_fifo_data_v3_hw(phy); | 	debugfs_read_fifo_data_v3_hw(phy); | ||||||
| 
 | 
 | ||||||
| 	debugfs_show_row_32_v3_hw(s, 0, HISI_SAS_FIFO_DATA_DW_SIZE * 4, | 	debugfs_show_row_32_v3_hw(s, 0, | ||||||
| 				  (__le32 *)phy->fifo.rd_data); | 			HISI_SAS_FIFO_DATA_DW_SIZE * HISI_SAS_REG_MEM_SIZE, | ||||||
|  | 			(__le32 *)phy->fifo.rd_data); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -4632,14 +4690,14 @@ static int debugfs_alloc_v3_hw(struct hisi_hba *hisi_hba, int dump_index) | ||||||
| 		struct hisi_sas_debugfs_regs *regs = | 		struct hisi_sas_debugfs_regs *regs = | ||||||
| 				&hisi_hba->debugfs_regs[dump_index][r]; | 				&hisi_hba->debugfs_regs[dump_index][r]; | ||||||
| 
 | 
 | ||||||
| 		sz = debugfs_reg_array_v3_hw[r]->count * 4; | 		sz = debugfs_reg_array_v3_hw[r]->count * HISI_SAS_REG_MEM_SIZE; | ||||||
| 		regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); | 		regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); | ||||||
| 		if (!regs->data) | 		if (!regs->data) | ||||||
| 			goto fail; | 			goto fail; | ||||||
| 		regs->hisi_hba = hisi_hba; | 		regs->hisi_hba = hisi_hba; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	sz = debugfs_port_reg.count * 4; | 	sz = debugfs_port_reg.count * HISI_SAS_REG_MEM_SIZE; | ||||||
| 	for (p = 0; p < hisi_hba->n_phy; p++) { | 	for (p = 0; p < hisi_hba->n_phy; p++) { | ||||||
| 		struct hisi_sas_debugfs_port *port = | 		struct hisi_sas_debugfs_port *port = | ||||||
| 				&hisi_hba->debugfs_port_reg[dump_index][p]; | 				&hisi_hba->debugfs_port_reg[dump_index][p]; | ||||||
|  | @ -4749,11 +4807,11 @@ static void debugfs_phy_down_cnt_init_v3_hw(struct hisi_hba *hisi_hba) | ||||||
| { | { | ||||||
| 	struct dentry *dir = debugfs_create_dir("phy_down_cnt", | 	struct dentry *dir = debugfs_create_dir("phy_down_cnt", | ||||||
| 						hisi_hba->debugfs_dir); | 						hisi_hba->debugfs_dir); | ||||||
| 	char name[16]; | 	char name[NAME_BUF_SIZE]; | ||||||
| 	int phy_no; | 	int phy_no; | ||||||
| 
 | 
 | ||||||
| 	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { | 	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { | ||||||
| 		snprintf(name, 16, "%d", phy_no); | 		snprintf(name, NAME_BUF_SIZE, "%d", phy_no); | ||||||
| 		debugfs_create_file(name, 0600, dir, | 		debugfs_create_file(name, 0600, dir, | ||||||
| 				    &hisi_hba->phy[phy_no], | 				    &hisi_hba->phy[phy_no], | ||||||
| 				    &debugfs_phy_down_cnt_v3_hw_fops); | 				    &debugfs_phy_down_cnt_v3_hw_fops); | ||||||
|  | @ -4938,7 +4996,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||||||
| 	shost->max_id = HISI_SAS_MAX_DEVICES; | 	shost->max_id = HISI_SAS_MAX_DEVICES; | ||||||
| 	shost->max_lun = ~0; | 	shost->max_lun = ~0; | ||||||
| 	shost->max_channel = 1; | 	shost->max_channel = 1; | ||||||
| 	shost->max_cmd_len = 16; | 	shost->max_cmd_len = HISI_SAS_MAX_CDB_LEN; | ||||||
| 	shost->can_queue = HISI_SAS_UNRESERVED_IPTT; | 	shost->can_queue = HISI_SAS_UNRESERVED_IPTT; | ||||||
| 	shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT; | 	shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT; | ||||||
| 	if (hisi_hba->iopoll_q_cnt) | 	if (hisi_hba->iopoll_q_cnt) | ||||||
|  | @ -5016,12 +5074,13 @@ hisi_sas_v3_destroy_irqs(struct pci_dev *pdev, struct hisi_hba *hisi_hba) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 1), hisi_hba); | 	devm_free_irq(&pdev->dev, pci_irq_vector(pdev, IRQ_PHY_UP_DOWN_INDEX), hisi_hba); | ||||||
| 	devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 2), hisi_hba); | 	devm_free_irq(&pdev->dev, pci_irq_vector(pdev, IRQ_CHL_INDEX), hisi_hba); | ||||||
| 	devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 11), hisi_hba); | 	devm_free_irq(&pdev->dev, pci_irq_vector(pdev, IRQ_AXI_INDEX), hisi_hba); | ||||||
| 	for (i = 0; i < hisi_hba->cq_nvecs; i++) { | 	for (i = 0; i < hisi_hba->cq_nvecs; i++) { | ||||||
| 		struct hisi_sas_cq *cq = &hisi_hba->cq[i]; | 		struct hisi_sas_cq *cq = &hisi_hba->cq[i]; | ||||||
| 		int nr = hisi_sas_intr_conv ? 16 : 16 + i; | 		int nr = hisi_sas_intr_conv ? BASE_VECTORS_V3_HW : | ||||||
|  | 					      BASE_VECTORS_V3_HW + i; | ||||||
| 
 | 
 | ||||||
| 		devm_free_irq(&pdev->dev, pci_irq_vector(pdev, nr), cq); | 		devm_free_irq(&pdev->dev, pci_irq_vector(pdev, nr), cq); | ||||||
| 	} | 	} | ||||||
|  | @ -5051,9 +5110,11 @@ static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev) | ||||||
| { | { | ||||||
| 	struct sas_ha_struct *sha = pci_get_drvdata(pdev); | 	struct sas_ha_struct *sha = pci_get_drvdata(pdev); | ||||||
| 	struct hisi_hba *hisi_hba = sha->lldd_ha; | 	struct hisi_hba *hisi_hba = sha->lldd_ha; | ||||||
|  | 	struct Scsi_Host *shost = hisi_hba->shost; | ||||||
| 	struct device *dev = hisi_hba->dev; | 	struct device *dev = hisi_hba->dev; | ||||||
| 	int rc; | 	int rc; | ||||||
| 
 | 
 | ||||||
|  | 	wait_event(shost->host_wait, !scsi_host_in_recovery(shost)); | ||||||
| 	dev_info(dev, "FLR prepare\n"); | 	dev_info(dev, "FLR prepare\n"); | ||||||
| 	down(&hisi_hba->sem); | 	down(&hisi_hba->sem); | ||||||
| 	set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); | 	set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); | ||||||
|  |  | ||||||
|  | @ -392,36 +392,6 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum sci_status sci_remote_device_reset(struct isci_remote_device *idev) |  | ||||||
| { |  | ||||||
| 	struct sci_base_state_machine *sm = &idev->sm; |  | ||||||
| 	enum sci_remote_device_states state = sm->current_state_id; |  | ||||||
| 
 |  | ||||||
| 	switch (state) { |  | ||||||
| 	case SCI_DEV_INITIAL: |  | ||||||
| 	case SCI_DEV_STOPPED: |  | ||||||
| 	case SCI_DEV_STARTING: |  | ||||||
| 	case SCI_SMP_DEV_IDLE: |  | ||||||
| 	case SCI_SMP_DEV_CMD: |  | ||||||
| 	case SCI_DEV_STOPPING: |  | ||||||
| 	case SCI_DEV_FAILED: |  | ||||||
| 	case SCI_DEV_RESETTING: |  | ||||||
| 	case SCI_DEV_FINAL: |  | ||||||
| 	default: |  | ||||||
| 		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", |  | ||||||
| 			 __func__, dev_state_name(state)); |  | ||||||
| 		return SCI_FAILURE_INVALID_STATE; |  | ||||||
| 	case SCI_DEV_READY: |  | ||||||
| 	case SCI_STP_DEV_IDLE: |  | ||||||
| 	case SCI_STP_DEV_CMD: |  | ||||||
| 	case SCI_STP_DEV_NCQ: |  | ||||||
| 	case SCI_STP_DEV_NCQ_ERROR: |  | ||||||
| 	case SCI_STP_DEV_AWAIT_RESET: |  | ||||||
| 		sci_change_state(sm, SCI_DEV_RESETTING); |  | ||||||
| 		return SCI_SUCCESS; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, | enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, | ||||||
| 						     u32 frame_index) | 						     u32 frame_index) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -159,21 +159,6 @@ enum sci_status sci_remote_device_stop( | ||||||
| 	struct isci_remote_device *idev, | 	struct isci_remote_device *idev, | ||||||
| 	u32 timeout); | 	u32 timeout); | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * sci_remote_device_reset() - This method will reset the device making it |  | ||||||
|  *    ready for operation. This method must be called anytime the device is |  | ||||||
|  *    reset either through a SMP phy control or a port hard reset request. |  | ||||||
|  * @remote_device: This parameter specifies the device to be reset. |  | ||||||
|  * |  | ||||||
|  * This method does not actually cause the device hardware to be reset. This |  | ||||||
|  * method resets the software object so that it will be operational after a |  | ||||||
|  * device hardware reset completes. An indication of whether the device reset |  | ||||||
|  * was accepted. SCI_SUCCESS This value is returned if the device reset is |  | ||||||
|  * started. |  | ||||||
|  */ |  | ||||||
| enum sci_status sci_remote_device_reset( |  | ||||||
| 	struct isci_remote_device *idev); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * enum sci_remote_device_states - This enumeration depicts all the states |  * enum sci_remote_device_states - This enumeration depicts all the states | ||||||
|  *    for the common remote device state machine. |  *    for the common remote device state machine. | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /*******************************************************************
 | /*******************************************************************
 | ||||||
|  * This file is part of the Emulex Linux Device Driver for         * |  * This file is part of the Emulex Linux Device Driver for         * | ||||||
|  * Fibre Channel Host Bus Adapters.                                * |  * Fibre Channel Host Bus Adapters.                                * | ||||||
|  * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * |  * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * | ||||||
|  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.  * |  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.  * | ||||||
|  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           * |  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           * | ||||||
|  * EMULEX and SLI are trademarks of Emulex.                        * |  * EMULEX and SLI are trademarks of Emulex.                        * | ||||||
|  | @ -291,6 +291,138 @@ lpfc_cmf_info_show(struct device *dev, struct device_attribute *attr, | ||||||
| 	return len; | 	return len; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static ssize_t | ||||||
|  | lpfc_vmid_info_show(struct device *dev, struct device_attribute *attr, | ||||||
|  | 		    char *buf) | ||||||
|  | { | ||||||
|  | 	struct Scsi_Host  *shost = class_to_shost(dev); | ||||||
|  | 	struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; | ||||||
|  | 	struct lpfc_hba   *phba = vport->phba; | ||||||
|  | 	struct lpfc_vmid  *vmp; | ||||||
|  | 	int  len = 0, i, j, k, cpu; | ||||||
|  | 	char hxstr[LPFC_MAX_VMID_SIZE * 3] = {0}; | ||||||
|  | 	struct timespec64 curr_tm; | ||||||
|  | 	struct lpfc_vmid_priority_range *vr; | ||||||
|  | 	u64 *lta, rct_acc = 0, max_lta = 0; | ||||||
|  | 	struct tm tm_val; | ||||||
|  | 
 | ||||||
|  | 	ktime_get_ts64(&curr_tm); | ||||||
|  | 
 | ||||||
|  | 	len += scnprintf(buf + len, PAGE_SIZE - len, "Key 'vmid':\n"); | ||||||
|  | 
 | ||||||
|  | 	/* if enabled continue, else return */ | ||||||
|  | 	if (lpfc_is_vmid_enabled(phba)) { | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 				 "lpfc VMID Page: ON\n\n"); | ||||||
|  | 	} else { | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 				 "lpfc VMID Page: OFF\n\n"); | ||||||
|  | 		return len; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* if using priority tagging */ | ||||||
|  | 	if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) { | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 				"VMID priority ranges:\n"); | ||||||
|  | 		vr = vport->vmid_priority.vmid_range; | ||||||
|  | 		for (i = 0; i < vport->vmid_priority.num_descriptors; ++i) { | ||||||
|  | 			len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 					"\t[x%x - x%x], qos: x%x\n", | ||||||
|  | 					vr->low, vr->high, vr->qos); | ||||||
|  | 			vr++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < phba->cfg_max_vmid; i++) { | ||||||
|  | 		vmp = &vport->vmid[i]; | ||||||
|  | 		max_lta = 0; | ||||||
|  | 
 | ||||||
|  | 		/* only if the slot is used */ | ||||||
|  | 		if (!(vmp->flag & LPFC_VMID_SLOT_USED) || | ||||||
|  | 		    !(vmp->flag & LPFC_VMID_REGISTERED)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		/* if using priority tagging */ | ||||||
|  | 		if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) { | ||||||
|  | 			len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 					"VEM ID: %02x:%02x:%02x:%02x:" | ||||||
|  | 					"%02x:%02x:%02x:%02x:%02x:%02x:" | ||||||
|  | 					"%02x:%02x:%02x:%02x:%02x:%02x\n", | ||||||
|  | 					vport->lpfc_vmid_host_uuid[0], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[1], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[2], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[3], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[4], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[5], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[6], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[7], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[8], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[9], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[10], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[11], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[12], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[13], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[14], | ||||||
|  | 					vport->lpfc_vmid_host_uuid[15]); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* IO stats */ | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 				"ID00 READs:%llx WRITEs:%llx\n", | ||||||
|  | 				vmp->io_rd_cnt, | ||||||
|  | 				vmp->io_wr_cnt); | ||||||
|  | 		for (j = 0, k = 0; j < strlen(vmp->host_vmid); j++, k += 3) | ||||||
|  | 			sprintf((char *)(hxstr + k), "%2x ", vmp->host_vmid[j]); | ||||||
|  | 		/* UUIDs */ | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, "UUID:\n"); | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", hxstr); | ||||||
|  | 
 | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, "String (%s)\n", | ||||||
|  | 				vmp->host_vmid); | ||||||
|  | 
 | ||||||
|  | 		if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) | ||||||
|  | 			len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 					"CS_CTL VMID: 0x%x\n", | ||||||
|  | 					vmp->un.cs_ctl_vmid); | ||||||
|  | 		else | ||||||
|  | 			len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 					"Application id: 0x%x\n", | ||||||
|  | 					vmp->un.app_id); | ||||||
|  | 
 | ||||||
|  | 		/* calculate the last access time */ | ||||||
|  | 		for_each_possible_cpu(cpu) { | ||||||
|  | 			lta = per_cpu_ptr(vmp->last_io_time, cpu); | ||||||
|  | 			if (!lta) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | 			/* if last access time is less than timeout */ | ||||||
|  | 			if (time_after((unsigned long)*lta, jiffies)) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | 			if (*lta > max_lta) | ||||||
|  | 				max_lta = *lta; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		rct_acc = jiffies_to_msecs(jiffies - max_lta) / 1000; | ||||||
|  | 		/* current time */ | ||||||
|  | 		time64_to_tm(ktime_get_real_seconds(), | ||||||
|  | 			     -(sys_tz.tz_minuteswest * 60) - rct_acc, &tm_val); | ||||||
|  | 
 | ||||||
|  | 		len += scnprintf(buf + len, PAGE_SIZE - len, | ||||||
|  | 				 "Last Access Time :" | ||||||
|  | 				 "%ld-%d-%dT%02d:%02d:%02d\n\n", | ||||||
|  | 				 1900 + tm_val.tm_year, tm_val.tm_mon + 1, | ||||||
|  | 				 tm_val.tm_mday, tm_val.tm_hour, | ||||||
|  | 				 tm_val.tm_min, tm_val.tm_sec); | ||||||
|  | 
 | ||||||
|  | 		if (len >= PAGE_SIZE) | ||||||
|  | 			return len; | ||||||
|  | 
 | ||||||
|  | 		memset(hxstr, 0, LPFC_MAX_VMID_SIZE * 3); | ||||||
|  | 	} | ||||||
|  | 	return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * lpfc_drvr_version_show - Return the Emulex driver string with version number |  * lpfc_drvr_version_show - Return the Emulex driver string with version number | ||||||
|  * @dev: class unused variable. |  * @dev: class unused variable. | ||||||
|  | @ -3011,6 +3143,7 @@ static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); | ||||||
| static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, | static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, | ||||||
| 		   NULL); | 		   NULL); | ||||||
| static DEVICE_ATTR(cmf_info, 0444, lpfc_cmf_info_show, NULL); | static DEVICE_ATTR(cmf_info, 0444, lpfc_cmf_info_show, NULL); | ||||||
|  | static DEVICE_ATTR_RO(lpfc_vmid_info); | ||||||
| 
 | 
 | ||||||
| #define WWN_SZ 8 | #define WWN_SZ 8 | ||||||
| /**
 | /**
 | ||||||
|  | @ -6117,6 +6250,7 @@ static struct attribute *lpfc_hba_attrs[] = { | ||||||
| 	&dev_attr_lpfc_vmid_inactivity_timeout.attr, | 	&dev_attr_lpfc_vmid_inactivity_timeout.attr, | ||||||
| 	&dev_attr_lpfc_vmid_app_header.attr, | 	&dev_attr_lpfc_vmid_app_header.attr, | ||||||
| 	&dev_attr_lpfc_vmid_priority_tagging.attr, | 	&dev_attr_lpfc_vmid_priority_tagging.attr, | ||||||
|  | 	&dev_attr_lpfc_vmid_info.attr, | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2687,8 +2687,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, | ||||||
| 	evt->wait_time_stamp = jiffies; | 	evt->wait_time_stamp = jiffies; | ||||||
| 	time_left = wait_event_interruptible_timeout( | 	time_left = wait_event_interruptible_timeout( | ||||||
| 		evt->wq, !list_empty(&evt->events_to_see), | 		evt->wq, !list_empty(&evt->events_to_see), | ||||||
| 		msecs_to_jiffies(1000 * | 		secs_to_jiffies(phba->fc_ratov * 2 + LPFC_DRVR_TIMEOUT)); | ||||||
| 			((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); |  | ||||||
| 	if (list_empty(&evt->events_to_see)) | 	if (list_empty(&evt->events_to_see)) | ||||||
| 		ret_val = (time_left) ? -EINTR : -ETIMEDOUT; | 		ret_val = (time_left) ? -EINTR : -ETIMEDOUT; | ||||||
| 	else { | 	else { | ||||||
|  | @ -3258,8 +3257,7 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job) | ||||||
| 	evt->waiting = 1; | 	evt->waiting = 1; | ||||||
| 	time_left = wait_event_interruptible_timeout( | 	time_left = wait_event_interruptible_timeout( | ||||||
| 		evt->wq, !list_empty(&evt->events_to_see), | 		evt->wq, !list_empty(&evt->events_to_see), | ||||||
| 		msecs_to_jiffies(1000 * | 		secs_to_jiffies(phba->fc_ratov * 2 + LPFC_DRVR_TIMEOUT)); | ||||||
| 			((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); |  | ||||||
| 	evt->waiting = 0; | 	evt->waiting = 0; | ||||||
| 	if (list_empty(&evt->events_to_see)) { | 	if (list_empty(&evt->events_to_see)) { | ||||||
| 		rc = (time_left) ? -EINTR : -ETIMEDOUT; | 		rc = (time_left) ? -EINTR : -ETIMEDOUT; | ||||||
|  |  | ||||||
|  | @ -161,7 +161,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | ||||||
| 	struct lpfc_hba   *phba; | 	struct lpfc_hba   *phba; | ||||||
| 	struct lpfc_work_evt *evtp; | 	struct lpfc_work_evt *evtp; | ||||||
| 	unsigned long iflags; | 	unsigned long iflags; | ||||||
| 	bool nvme_reg = false; | 	bool drop_initial_node_ref = false; | ||||||
| 
 | 
 | ||||||
| 	ndlp = ((struct lpfc_rport_data *)rport->dd_data)->pnode; | 	ndlp = ((struct lpfc_rport_data *)rport->dd_data)->pnode; | ||||||
| 	if (!ndlp) | 	if (!ndlp) | ||||||
|  | @ -188,8 +188,13 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | ||||||
| 		spin_lock_irqsave(&ndlp->lock, iflags); | 		spin_lock_irqsave(&ndlp->lock, iflags); | ||||||
| 		ndlp->rport = NULL; | 		ndlp->rport = NULL; | ||||||
| 
 | 
 | ||||||
| 		if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) | 		/* Only 1 thread can drop the initial node reference.
 | ||||||
| 			nvme_reg = true; | 		 * If not registered for NVME and NLP_DROPPED flag is | ||||||
|  | 		 * clear, remove the initial reference. | ||||||
|  | 		 */ | ||||||
|  | 		if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) | ||||||
|  | 			if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) | ||||||
|  | 				drop_initial_node_ref = true; | ||||||
| 
 | 
 | ||||||
| 		/* The scsi_transport is done with the rport so lpfc cannot
 | 		/* The scsi_transport is done with the rport so lpfc cannot
 | ||||||
| 		 * call to unregister. | 		 * call to unregister. | ||||||
|  | @ -200,13 +205,16 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | ||||||
| 			/* If NLP_XPT_REGD was cleared in lpfc_nlp_unreg_node,
 | 			/* If NLP_XPT_REGD was cleared in lpfc_nlp_unreg_node,
 | ||||||
| 			 * unregister calls were made to the scsi and nvme | 			 * unregister calls were made to the scsi and nvme | ||||||
| 			 * transports and refcnt was already decremented. Clear | 			 * transports and refcnt was already decremented. Clear | ||||||
| 			 * the NLP_XPT_REGD flag only if the NVME Rport is | 			 * the NLP_XPT_REGD flag only if the NVME nrport is | ||||||
| 			 * confirmed unregistered. | 			 * confirmed unregistered. | ||||||
| 			 */ | 			 */ | ||||||
| 			if (!nvme_reg && ndlp->fc4_xpt_flags & NLP_XPT_REGD) { | 			if (ndlp->fc4_xpt_flags & NLP_XPT_REGD) { | ||||||
| 				ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; | 				if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) | ||||||
|  | 					ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; | ||||||
| 				spin_unlock_irqrestore(&ndlp->lock, iflags); | 				spin_unlock_irqrestore(&ndlp->lock, iflags); | ||||||
| 				lpfc_nlp_put(ndlp); /* may free ndlp */ | 
 | ||||||
|  | 				/* Release scsi transport reference */ | ||||||
|  | 				lpfc_nlp_put(ndlp); | ||||||
| 			} else { | 			} else { | ||||||
| 				spin_unlock_irqrestore(&ndlp->lock, iflags); | 				spin_unlock_irqrestore(&ndlp->lock, iflags); | ||||||
| 			} | 			} | ||||||
|  | @ -214,14 +222,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | ||||||
| 			spin_unlock_irqrestore(&ndlp->lock, iflags); | 			spin_unlock_irqrestore(&ndlp->lock, iflags); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/* Only 1 thread can drop the initial node reference.  If
 | 		if (drop_initial_node_ref) | ||||||
| 		 * another thread has set NLP_DROPPED, this thread is done. | 			lpfc_nlp_put(ndlp); | ||||||
| 		 */ |  | ||||||
| 		if (nvme_reg || test_bit(NLP_DROPPED, &ndlp->nlp_flag)) |  | ||||||
| 			return; |  | ||||||
| 
 |  | ||||||
| 		set_bit(NLP_DROPPED, &ndlp->nlp_flag); |  | ||||||
| 		lpfc_nlp_put(ndlp); |  | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -4695,9 +4697,7 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||||||
| 	if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) { | 	if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) { | ||||||
| 		vport->phba->nport_event_cnt++; | 		vport->phba->nport_event_cnt++; | ||||||
| 		if (vport->phba->nvmet_support == 0) { | 		if (vport->phba->nvmet_support == 0) { | ||||||
| 			/* Start devloss if target. */ | 			lpfc_nvme_unregister_port(vport, ndlp); | ||||||
| 			if (ndlp->nlp_type & NLP_NVME_TARGET) |  | ||||||
| 				lpfc_nvme_unregister_port(vport, ndlp); |  | ||||||
| 		} else { | 		} else { | ||||||
| 			/* NVMET has no upcall. */ | 			/* NVMET has no upcall. */ | ||||||
| 			lpfc_nlp_put(ndlp); | 			lpfc_nlp_put(ndlp); | ||||||
|  | @ -5053,7 +5053,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, | ||||||
| 		case CMD_GEN_REQUEST64_CR: | 		case CMD_GEN_REQUEST64_CR: | ||||||
| 			if (iocb->ndlp == ndlp) | 			if (iocb->ndlp == ndlp) | ||||||
| 				return 1; | 				return 1; | ||||||
| 			fallthrough; | 			break; | ||||||
| 		case CMD_ELS_REQUEST64_CR: | 		case CMD_ELS_REQUEST64_CR: | ||||||
| 			if (remote_id == ndlp->nlp_DID) | 			if (remote_id == ndlp->nlp_DID) | ||||||
| 				return 1; | 				return 1; | ||||||
|  |  | ||||||
|  | @ -1907,6 +1907,9 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, | ||||||
| 	uint32_t intr_mode; | 	uint32_t intr_mode; | ||||||
| 	LPFC_MBOXQ_t *mboxq; | 	LPFC_MBOXQ_t *mboxq; | ||||||
| 
 | 
 | ||||||
|  | 	/* Notifying the transport that the targets are going offline. */ | ||||||
|  | 	lpfc_scsi_dev_block(phba); | ||||||
|  | 
 | ||||||
| 	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= | 	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= | ||||||
| 	    LPFC_SLI_INTF_IF_TYPE_2) { | 	    LPFC_SLI_INTF_IF_TYPE_2) { | ||||||
| 		/*
 | 		/*
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /*******************************************************************
 | /*******************************************************************
 | ||||||
|  * This file is part of the Emulex Linux Device Driver for         * |  * This file is part of the Emulex Linux Device Driver for         * | ||||||
|  * Fibre Channel Host Bus Adapters.                                * |  * Fibre Channel Host Bus Adapters.                                * | ||||||
|  * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * |  * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * | ||||||
|  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.  * |  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.  * | ||||||
|  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           * |  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           * | ||||||
|  * EMULEX and SLI are trademarks of Emulex.                        * |  * EMULEX and SLI are trademarks of Emulex.                        * | ||||||
|  | @ -2508,7 +2508,10 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||||||
| 				 "6031 RemotePort Registration failed " | 				 "6031 RemotePort Registration failed " | ||||||
| 				 "err: %d, DID x%06x ref %u\n", | 				 "err: %d, DID x%06x ref %u\n", | ||||||
| 				 ret, ndlp->nlp_DID, kref_read(&ndlp->kref)); | 				 ret, ndlp->nlp_DID, kref_read(&ndlp->kref)); | ||||||
| 		lpfc_nlp_put(ndlp); | 
 | ||||||
|  | 		/* Only release reference if one was taken for this request */ | ||||||
|  | 		if (!oldrport) | ||||||
|  | 			lpfc_nlp_put(ndlp); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
|  | @ -2614,7 +2617,8 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||||||
| 	 * clear any rport state until the transport calls back. | 	 * clear any rport state until the transport calls back. | ||||||
| 	 */ | 	 */ | ||||||
| 
 | 
 | ||||||
| 	if (ndlp->nlp_type & NLP_NVME_TARGET) { | 	if ((ndlp->nlp_type & NLP_NVME_TARGET) || | ||||||
|  | 	    (remoteport->port_role & FC_PORT_ROLE_NVME_TARGET)) { | ||||||
| 		/* No concern about the role change on the nvme remoteport.
 | 		/* No concern about the role change on the nvme remoteport.
 | ||||||
| 		 * The transport will update it. | 		 * The transport will update it. | ||||||
| 		 */ | 		 */ | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /*******************************************************************
 | /*******************************************************************
 | ||||||
|  * This file is part of the Emulex Linux Device Driver for         * |  * This file is part of the Emulex Linux Device Driver for         * | ||||||
|  * Fibre Channel Host Bus Adapters.                                * |  * Fibre Channel Host Bus Adapters.                                * | ||||||
|  * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * |  * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * | ||||||
|  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.     * |  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.     * | ||||||
|  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           * |  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           * | ||||||
|  * EMULEX and SLI are trademarks of Emulex.                        * |  * EMULEX and SLI are trademarks of Emulex.                        * | ||||||
|  | @ -3926,12 +3926,19 @@ void lpfc_poll_eratt(struct timer_list *t) | ||||||
| 	uint64_t sli_intr, cnt; | 	uint64_t sli_intr, cnt; | ||||||
| 
 | 
 | ||||||
| 	phba = from_timer(phba, t, eratt_poll); | 	phba = from_timer(phba, t, eratt_poll); | ||||||
| 	if (!test_bit(HBA_SETUP, &phba->hba_flag)) |  | ||||||
| 		return; |  | ||||||
| 
 | 
 | ||||||
| 	if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) | 	if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	if (phba->sli_rev == LPFC_SLI_REV4 && | ||||||
|  | 	    !test_bit(HBA_SETUP, &phba->hba_flag)) { | ||||||
|  | 		lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | ||||||
|  | 				"0663 HBA still initializing 0x%lx, restart " | ||||||
|  | 				"timer\n", | ||||||
|  | 				phba->hba_flag); | ||||||
|  | 		goto restart_timer; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* Here we will also keep track of interrupts per sec of the hba */ | 	/* Here we will also keep track of interrupts per sec of the hba */ | ||||||
| 	sli_intr = phba->sli.slistat.sli_intr; | 	sli_intr = phba->sli.slistat.sli_intr; | ||||||
| 
 | 
 | ||||||
|  | @ -3950,13 +3957,16 @@ void lpfc_poll_eratt(struct timer_list *t) | ||||||
| 	/* Check chip HA register for error event */ | 	/* Check chip HA register for error event */ | ||||||
| 	eratt = lpfc_sli_check_eratt(phba); | 	eratt = lpfc_sli_check_eratt(phba); | ||||||
| 
 | 
 | ||||||
| 	if (eratt) | 	if (eratt) { | ||||||
| 		/* Tell the worker thread there is work to do */ | 		/* Tell the worker thread there is work to do */ | ||||||
| 		lpfc_worker_wake_up(phba); | 		lpfc_worker_wake_up(phba); | ||||||
| 	else | 		return; | ||||||
| 		/* Restart the timer for next eratt poll */ | 	} | ||||||
| 		mod_timer(&phba->eratt_poll, | 
 | ||||||
| 			  jiffies + secs_to_jiffies(phba->eratt_poll_interval)); | restart_timer: | ||||||
|  | 	/* Restart the timer for next eratt poll */ | ||||||
|  | 	mod_timer(&phba->eratt_poll, | ||||||
|  | 		  jiffies + secs_to_jiffies(phba->eratt_poll_interval)); | ||||||
| 	return; | 	return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -6003,9 +6013,9 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) | ||||||
| 	phba->sli4_hba.flash_id = bf_get(lpfc_cntl_attr_flash_id, cntl_attr); | 	phba->sli4_hba.flash_id = bf_get(lpfc_cntl_attr_flash_id, cntl_attr); | ||||||
| 	phba->sli4_hba.asic_rev = bf_get(lpfc_cntl_attr_asic_rev, cntl_attr); | 	phba->sli4_hba.asic_rev = bf_get(lpfc_cntl_attr_asic_rev, cntl_attr); | ||||||
| 
 | 
 | ||||||
| 	memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion)); | 	memcpy(phba->BIOSVersion, cntl_attr->bios_ver_str, | ||||||
| 	strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str, |  | ||||||
| 		sizeof(phba->BIOSVersion)); | 		sizeof(phba->BIOSVersion)); | ||||||
|  | 	phba->BIOSVersion[sizeof(phba->BIOSVersion) - 1] = '\0'; | ||||||
| 
 | 
 | ||||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | 	lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | ||||||
| 			"3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s, " | 			"3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s, " | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ | ||||||
|  * included with this package.                                     * |  * included with this package.                                     * | ||||||
|  *******************************************************************/ |  *******************************************************************/ | ||||||
| 
 | 
 | ||||||
| #define LPFC_DRIVER_VERSION "14.4.0.8" | #define LPFC_DRIVER_VERSION "14.4.0.9" | ||||||
| #define LPFC_DRIVER_NAME		"lpfc" | #define LPFC_DRIVER_NAME		"lpfc" | ||||||
| 
 | 
 | ||||||
| /* Used for SLI 2/3 */ | /* Used for SLI 2/3 */ | ||||||
|  |  | ||||||
|  | @ -505,7 +505,7 @@ lpfc_send_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||||||
| 		wait_event_timeout(waitq, | 		wait_event_timeout(waitq, | ||||||
| 				   !test_bit(NLP_WAIT_FOR_LOGO, | 				   !test_bit(NLP_WAIT_FOR_LOGO, | ||||||
| 					     &ndlp->save_flags), | 					     &ndlp->save_flags), | ||||||
| 				   msecs_to_jiffies(phba->fc_ratov * 2000)); | 				   secs_to_jiffies(phba->fc_ratov * 2)); | ||||||
| 
 | 
 | ||||||
| 		if (!test_bit(NLP_WAIT_FOR_LOGO, &ndlp->save_flags)) | 		if (!test_bit(NLP_WAIT_FOR_LOGO, &ndlp->save_flags)) | ||||||
| 			goto logo_cmpl; | 			goto logo_cmpl; | ||||||
|  | @ -703,7 +703,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) | ||||||
| 				wait_event_timeout(waitq, | 				wait_event_timeout(waitq, | ||||||
| 				   !test_bit(NLP_WAIT_FOR_DA_ID, | 				   !test_bit(NLP_WAIT_FOR_DA_ID, | ||||||
| 					     &ndlp->save_flags), | 					     &ndlp->save_flags), | ||||||
| 				   msecs_to_jiffies(phba->fc_ratov * 2000)); | 				   secs_to_jiffies(phba->fc_ratov * 2)); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT | LOG_ELS, | 			lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT | LOG_ELS, | ||||||
|  |  | ||||||
|  | @ -985,6 +985,10 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc, | ||||||
| 				goto out; | 				goto out; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		dprint_event_bh(mrioc, | ||||||
|  | 		    "exposed target device with handle(0x%04x), perst_id(%d)\n", | ||||||
|  | 		    tgtdev->dev_handle, perst_id); | ||||||
|  | 		goto out; | ||||||
| 	} else | 	} else | ||||||
| 		mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev); | 		mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev); | ||||||
| out: | out: | ||||||
|  | @ -1344,9 +1348,9 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 	    (struct mpi3_event_data_device_status_change *)fwevt->event_data; | 	    (struct mpi3_event_data_device_status_change *)fwevt->event_data; | ||||||
| 
 | 
 | ||||||
| 	dev_handle = le16_to_cpu(evtdata->dev_handle); | 	dev_handle = le16_to_cpu(evtdata->dev_handle); | ||||||
| 	ioc_info(mrioc, | 	dprint_event_bh(mrioc, | ||||||
| 	    "%s :device status change: handle(0x%04x): reason code(0x%x)\n", | 	    "processing device status change event bottom half for handle(0x%04x), rc(0x%02x)\n", | ||||||
| 	    __func__, dev_handle, evtdata->reason_code); | 	    dev_handle, evtdata->reason_code); | ||||||
| 	switch (evtdata->reason_code) { | 	switch (evtdata->reason_code) { | ||||||
| 	case MPI3_EVENT_DEV_STAT_RC_HIDDEN: | 	case MPI3_EVENT_DEV_STAT_RC_HIDDEN: | ||||||
| 		delete = 1; | 		delete = 1; | ||||||
|  | @ -1365,8 +1369,13 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); | 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); | ||||||
| 	if (!tgtdev) | 	if (!tgtdev) { | ||||||
|  | 		dprint_event_bh(mrioc, | ||||||
|  | 		    "processing device status change event bottom half,\n" | ||||||
|  | 		    "cannot identify target device for handle(0x%04x), rc(0x%02x)\n", | ||||||
|  | 		    dev_handle, evtdata->reason_code); | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
| 	if (uhide) { | 	if (uhide) { | ||||||
| 		tgtdev->is_hidden = 0; | 		tgtdev->is_hidden = 0; | ||||||
| 		if (!tgtdev->host_exposed) | 		if (!tgtdev->host_exposed) | ||||||
|  | @ -1406,12 +1415,17 @@ static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 
 | 
 | ||||||
| 	perst_id = le16_to_cpu(dev_pg0->persistent_id); | 	perst_id = le16_to_cpu(dev_pg0->persistent_id); | ||||||
| 	dev_handle = le16_to_cpu(dev_pg0->dev_handle); | 	dev_handle = le16_to_cpu(dev_pg0->dev_handle); | ||||||
| 	ioc_info(mrioc, | 	dprint_event_bh(mrioc, | ||||||
| 	    "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n", | 	    "processing device info change event bottom half for handle(0x%04x), perst_id(%d)\n", | ||||||
| 	    __func__, dev_handle, perst_id); | 	    dev_handle, perst_id); | ||||||
| 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); | 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); | ||||||
| 	if (!tgtdev) | 	if (!tgtdev) { | ||||||
|  | 		dprint_event_bh(mrioc, | ||||||
|  | 		    "cannot identify target device for  device info\n" | ||||||
|  | 		    "change event handle(0x%04x), perst_id(%d)\n", | ||||||
|  | 		    dev_handle, perst_id); | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
| 	mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false); | 	mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false); | ||||||
| 	if (!tgtdev->is_hidden && !tgtdev->host_exposed) | 	if (!tgtdev->is_hidden && !tgtdev->host_exposed) | ||||||
| 		mpi3mr_report_tgtdev_to_host(mrioc, perst_id); | 		mpi3mr_report_tgtdev_to_host(mrioc, perst_id); | ||||||
|  | @ -2012,8 +2026,11 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 	mpi3mr_fwevt_del_from_list(mrioc, fwevt); | 	mpi3mr_fwevt_del_from_list(mrioc, fwevt); | ||||||
| 	mrioc->current_event = fwevt; | 	mrioc->current_event = fwevt; | ||||||
| 
 | 
 | ||||||
| 	if (mrioc->stop_drv_processing) | 	if (mrioc->stop_drv_processing) { | ||||||
|  | 		dprint_event_bh(mrioc, "ignoring event(0x%02x) in the bottom half handler\n" | ||||||
|  | 				"due to stop_drv_processing\n", fwevt->event_id); | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (mrioc->unrecoverable) { | 	if (mrioc->unrecoverable) { | ||||||
| 		dprint_event_bh(mrioc, | 		dprint_event_bh(mrioc, | ||||||
|  | @ -2025,6 +2042,9 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 	if (!fwevt->process_evt) | 	if (!fwevt->process_evt) | ||||||
| 		goto evt_ack; | 		goto evt_ack; | ||||||
| 
 | 
 | ||||||
|  | 	dprint_event_bh(mrioc, "processing event(0x%02x) in the bottom half handler\n", | ||||||
|  | 	    fwevt->event_id); | ||||||
|  | 
 | ||||||
| 	switch (fwevt->event_id) { | 	switch (fwevt->event_id) { | ||||||
| 	case MPI3_EVENT_DEVICE_ADDED: | 	case MPI3_EVENT_DEVICE_ADDED: | ||||||
| 	{ | 	{ | ||||||
|  | @ -2763,6 +2783,9 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc, | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	dev_handle = le16_to_cpu(evtdata->dev_handle); | 	dev_handle = le16_to_cpu(evtdata->dev_handle); | ||||||
|  | 	dprint_event_th(mrioc, | ||||||
|  | 	    "device status change event top half with rc(0x%02x) for handle(0x%04x)\n", | ||||||
|  | 	    evtdata->reason_code, dev_handle); | ||||||
| 
 | 
 | ||||||
| 	switch (evtdata->reason_code) { | 	switch (evtdata->reason_code) { | ||||||
| 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT: | 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT: | ||||||
|  | @ -2786,8 +2809,12 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); | 	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); | ||||||
| 	if (!tgtdev) | 	if (!tgtdev) { | ||||||
|  | 		dprint_event_th(mrioc, | ||||||
|  | 		    "processing device status change event could not identify device for handle(0x%04x)\n", | ||||||
|  | 		    dev_handle); | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
| 	if (hide) | 	if (hide) | ||||||
| 		tgtdev->is_hidden = hide; | 		tgtdev->is_hidden = hide; | ||||||
| 	if (tgtdev->starget && tgtdev->starget->hostdata) { | 	if (tgtdev->starget && tgtdev->starget->hostdata) { | ||||||
|  | @ -2863,13 +2890,13 @@ static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc, | ||||||
| 	u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout); | 	u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout); | ||||||
| 
 | 
 | ||||||
| 	if (shutdown_timeout <= 0) { | 	if (shutdown_timeout <= 0) { | ||||||
| 		ioc_warn(mrioc, | 		dprint_event_th(mrioc, | ||||||
| 		    "%s :Invalid Shutdown Timeout received = %d\n", | 		    "%s :Invalid Shutdown Timeout received = %d\n", | ||||||
| 		    __func__, shutdown_timeout); | 		    __func__, shutdown_timeout); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ioc_info(mrioc, | 	dprint_event_th(mrioc, | ||||||
| 	    "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n", | 	    "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n", | ||||||
| 	    __func__, mrioc->facts.shutdown_timeout, shutdown_timeout); | 	    __func__, mrioc->facts.shutdown_timeout, shutdown_timeout); | ||||||
| 	mrioc->facts.shutdown_timeout = shutdown_timeout; | 	mrioc->facts.shutdown_timeout = shutdown_timeout; | ||||||
|  | @ -2945,9 +2972,9 @@ void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc) | ||||||
|  * @mrioc: Adapter instance reference |  * @mrioc: Adapter instance reference | ||||||
|  * @event_reply: event data |  * @event_reply: event data | ||||||
|  * |  * | ||||||
|  * Identify whteher the event has to handled and acknowledged |  * Identifies whether the event has to be handled and acknowledged, | ||||||
|  * and either process the event in the tophalf and/or schedule a |  * and either processes the event in the top-half and/or schedule a | ||||||
|  * bottom half through mpi3mr_fwevt_worker. |  * bottom-half through mpi3mr_fwevt_worker(). | ||||||
|  * |  * | ||||||
|  * Return: Nothing |  * Return: Nothing | ||||||
|  */ |  */ | ||||||
|  | @ -2974,9 +3001,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, | ||||||
| 		struct mpi3_device_page0 *dev_pg0 = | 		struct mpi3_device_page0 *dev_pg0 = | ||||||
| 		    (struct mpi3_device_page0 *)event_reply->event_data; | 		    (struct mpi3_device_page0 *)event_reply->event_data; | ||||||
| 		if (mpi3mr_create_tgtdev(mrioc, dev_pg0)) | 		if (mpi3mr_create_tgtdev(mrioc, dev_pg0)) | ||||||
| 			ioc_err(mrioc, | 			dprint_event_th(mrioc, | ||||||
| 			    "%s :Failed to add device in the device add event\n", | 				"failed to process device added event for handle(0x%04x),\n" | ||||||
| 			    __func__); | 				"perst_id(%d) in the event top half handler\n", | ||||||
|  | 				le16_to_cpu(dev_pg0->dev_handle), | ||||||
|  | 				le16_to_cpu(dev_pg0->persistent_id)); | ||||||
| 		else | 		else | ||||||
| 			process_evt_bh = 1; | 			process_evt_bh = 1; | ||||||
| 		break; | 		break; | ||||||
|  | @ -3039,11 +3068,15 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 	if (process_evt_bh || ack_req) { | 	if (process_evt_bh || ack_req) { | ||||||
|  | 		dprint_event_th(mrioc, | ||||||
|  | 			"scheduling bottom half handler for event(0x%02x),ack_required=%d\n", | ||||||
|  | 			evt_type, ack_req); | ||||||
| 		sz = event_reply->event_data_length * 4; | 		sz = event_reply->event_data_length * 4; | ||||||
| 		fwevt = mpi3mr_alloc_fwevt(sz); | 		fwevt = mpi3mr_alloc_fwevt(sz); | ||||||
| 		if (!fwevt) { | 		if (!fwevt) { | ||||||
| 			ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n", | 			dprint_event_th(mrioc, | ||||||
| 			    __func__, __FILE__, __LINE__, __func__); | 				"failed to schedule bottom half handler for\n" | ||||||
|  | 				"event(0x%02x), ack_required=%d\n", evt_type, ack_req); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2869,8 +2869,9 @@ _ctl_get_mpt_mctp_passthru_adapter(int dev_index) | ||||||
| 		if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) { | 		if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) { | ||||||
| 			if (count == dev_index) { | 			if (count == dev_index) { | ||||||
| 				spin_unlock(&gioc_lock); | 				spin_unlock(&gioc_lock); | ||||||
| 				return 0; | 				return ioc; | ||||||
| 			} | 			} | ||||||
|  | 			count++; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	spin_unlock(&gioc_lock); | 	spin_unlock(&gioc_lock); | ||||||
|  |  | ||||||
|  | @ -101,8 +101,8 @@ enum sas_sata_vsp_regs { | ||||||
| 	VSR_PHY_MODE9		= 0x09, /* Test */ | 	VSR_PHY_MODE9		= 0x09, /* Test */ | ||||||
| 	VSR_PHY_MODE10		= 0x0A, /* Power */ | 	VSR_PHY_MODE10		= 0x0A, /* Power */ | ||||||
| 	VSR_PHY_MODE11		= 0x0B, /* Phy Mode */ | 	VSR_PHY_MODE11		= 0x0B, /* Phy Mode */ | ||||||
| 	VSR_PHY_VS0		= 0x0C, /* Vednor Specific 0 */ | 	VSR_PHY_VS0		= 0x0C, /* Vendor Specific 0 */ | ||||||
| 	VSR_PHY_VS1		= 0x0D, /* Vednor Specific 1 */ | 	VSR_PHY_VS1		= 0x0D, /* Vendor Specific 1 */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum chip_register_bits { | enum chip_register_bits { | ||||||
|  |  | ||||||
|  | @ -644,7 +644,7 @@ static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL); | ||||||
| #define FLASH_CMD_SET_NVMD    0x02 | #define FLASH_CMD_SET_NVMD    0x02 | ||||||
| 
 | 
 | ||||||
| struct flash_command { | struct flash_command { | ||||||
|      u8      command[8]; |      u8      command[8] __nonstring; | ||||||
|      int     code; |      int     code; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -103,25 +103,3 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, | ||||||
| ret: | ret: | ||||||
| 	va_end(va); | 	va_end(va); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| int |  | ||||||
| qedi_create_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter) |  | ||||||
| { |  | ||||||
| 	int ret = 0; |  | ||||||
| 
 |  | ||||||
| 	for (; iter->name; iter++) { |  | ||||||
| 		ret = sysfs_create_bin_file(&shost->shost_gendev.kobj, |  | ||||||
| 					    iter->attr); |  | ||||||
| 		if (ret) |  | ||||||
| 			pr_err("Unable to create sysfs %s attr, err(%d).\n", |  | ||||||
| 			       iter->name, ret); |  | ||||||
| 	} |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void |  | ||||||
| qedi_remove_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter) |  | ||||||
| { |  | ||||||
| 	for (; iter->name; iter++) |  | ||||||
| 		sysfs_remove_bin_file(&shost->shost_gendev.kobj, iter->attr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -87,18 +87,6 @@ void qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, | ||||||
| void qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, | void qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, | ||||||
| 		   u32 info, const char *fmt, ...); | 		   u32 info, const char *fmt, ...); | ||||||
| 
 | 
 | ||||||
| struct Scsi_Host; |  | ||||||
| 
 |  | ||||||
| struct sysfs_bin_attrs { |  | ||||||
| 	char *name; |  | ||||||
| 	const struct bin_attribute *attr; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| int qedi_create_sysfs_attr(struct Scsi_Host *shost, |  | ||||||
| 			   struct sysfs_bin_attrs *iter); |  | ||||||
| void qedi_remove_sysfs_attr(struct Scsi_Host *shost, |  | ||||||
| 			    struct sysfs_bin_attrs *iter); |  | ||||||
| 
 |  | ||||||
| /* DebugFS related code */ | /* DebugFS related code */ | ||||||
| struct qedi_list_of_funcs { | struct qedi_list_of_funcs { | ||||||
| 	char *oper_str; | 	char *oper_str; | ||||||
|  |  | ||||||
|  | @ -45,7 +45,6 @@ int qedi_iscsi_cleanup_task(struct iscsi_task *task, | ||||||
| void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd); | void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd); | ||||||
| void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, | void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, | ||||||
| 			 struct qedi_cmd *qedi_cmd); | 			 struct qedi_cmd *qedi_cmd); | ||||||
| void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt); |  | ||||||
| void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, int16_t *tid); | void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, int16_t *tid); | ||||||
| void qedi_process_iscsi_error(struct qedi_endpoint *ep, | void qedi_process_iscsi_error(struct qedi_endpoint *ep, | ||||||
| 			      struct iscsi_eqe_data *data); | 			      struct iscsi_eqe_data *data); | ||||||
|  |  | ||||||
|  | @ -1877,14 +1877,6 @@ void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid) | ||||||
| 	WARN_ON(1); | 	WARN_ON(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt) |  | ||||||
| { |  | ||||||
| 	*proto_itt = qedi->itt_map[tid].itt; |  | ||||||
| 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, |  | ||||||
| 		  "Get itt map tid [0x%x with proto itt[0x%x]", |  | ||||||
| 		  tid, *proto_itt); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) | struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) | ||||||
| { | { | ||||||
| 	struct qedi_cmd *cmd = NULL; | 	struct qedi_cmd *cmd = NULL; | ||||||
|  |  | ||||||
|  | @ -2705,59 +2705,6 @@ ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, const void *buf, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * This function is for formatting and logging log messages. |  | ||||||
|  * It is to be used when vha is available. It formats the message |  | ||||||
|  * and logs it to the messages file. All the messages will be logged |  | ||||||
|  * irrespective of value of ql2xextended_error_logging. |  | ||||||
|  * parameters: |  | ||||||
|  * level: The level of the log messages to be printed in the |  | ||||||
|  *        messages file. |  | ||||||
|  * vha:   Pointer to the scsi_qla_host_t |  | ||||||
|  * id:    This is a unique id for the level. It identifies the |  | ||||||
|  *        part of the code from where the message originated. |  | ||||||
|  * msg:   The message to be displayed. |  | ||||||
|  */ |  | ||||||
| void |  | ||||||
| ql_log_qp(uint32_t level, struct qla_qpair *qpair, int32_t id, |  | ||||||
|     const char *fmt, ...) |  | ||||||
| { |  | ||||||
| 	va_list va; |  | ||||||
| 	struct va_format vaf; |  | ||||||
| 	char pbuf[128]; |  | ||||||
| 
 |  | ||||||
| 	if (level > ql_errlev) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	ql_ktrace(0, level, pbuf, NULL, qpair ? qpair->vha : NULL, id, fmt); |  | ||||||
| 
 |  | ||||||
| 	if (!pbuf[0]) /* set by ql_ktrace */ |  | ||||||
| 		ql_dbg_prefix(pbuf, ARRAY_SIZE(pbuf), NULL, |  | ||||||
| 			      qpair ? qpair->vha : NULL, id); |  | ||||||
| 
 |  | ||||||
| 	va_start(va, fmt); |  | ||||||
| 
 |  | ||||||
| 	vaf.fmt = fmt; |  | ||||||
| 	vaf.va = &va; |  | ||||||
| 
 |  | ||||||
| 	switch (level) { |  | ||||||
| 	case ql_log_fatal: /* FATAL LOG */ |  | ||||||
| 		pr_crit("%s%pV", pbuf, &vaf); |  | ||||||
| 		break; |  | ||||||
| 	case ql_log_warn: |  | ||||||
| 		pr_err("%s%pV", pbuf, &vaf); |  | ||||||
| 		break; |  | ||||||
| 	case ql_log_info: |  | ||||||
| 		pr_warn("%s%pV", pbuf, &vaf); |  | ||||||
| 		break; |  | ||||||
| 	default: |  | ||||||
| 		pr_info("%s%pV", pbuf, &vaf); |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	va_end(va); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * This function is for formatting and logging debug information. |  * This function is for formatting and logging debug information. | ||||||
|  * It is to be used when vha is available. It formats the message |  * It is to be used when vha is available. It formats the message | ||||||
|  |  | ||||||
|  | @ -334,9 +334,6 @@ ql_log(uint, scsi_qla_host_t *vha, uint, const char *fmt, ...); | ||||||
| void __attribute__((format (printf, 4, 5))) | void __attribute__((format (printf, 4, 5))) | ||||||
| ql_log_pci(uint, struct pci_dev *pdev, uint, const char *fmt, ...); | ql_log_pci(uint, struct pci_dev *pdev, uint, const char *fmt, ...); | ||||||
| 
 | 
 | ||||||
| void __attribute__((format (printf, 4, 5))) |  | ||||||
| ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...); |  | ||||||
| 
 |  | ||||||
| /* Debug Levels */ | /* Debug Levels */ | ||||||
| /* The 0x40000000 is the max value any debug level can have
 | /* The 0x40000000 is the max value any debug level can have
 | ||||||
|  * as ql2xextended_error_logging is of type signed int |  * as ql2xextended_error_logging is of type signed int | ||||||
|  |  | ||||||
|  | @ -164,10 +164,8 @@ extern int ql2xsmartsan; | ||||||
| extern int ql2xallocfwdump; | extern int ql2xallocfwdump; | ||||||
| extern int ql2xextended_error_logging; | extern int ql2xextended_error_logging; | ||||||
| extern int ql2xextended_error_logging_ktrace; | extern int ql2xextended_error_logging_ktrace; | ||||||
| extern int ql2xiidmaenable; |  | ||||||
| extern int ql2xmqsupport; | extern int ql2xmqsupport; | ||||||
| extern int ql2xfwloadbin; | extern int ql2xfwloadbin; | ||||||
| extern int ql2xetsenable; |  | ||||||
| extern int ql2xshiftctondsd; | extern int ql2xshiftctondsd; | ||||||
| extern int ql2xdbwr; | extern int ql2xdbwr; | ||||||
| extern int ql2xasynctmfenable; | extern int ql2xasynctmfenable; | ||||||
|  | @ -720,7 +718,6 @@ extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); | ||||||
| extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); | extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); | ||||||
| extern int qla2x00_fdmi_register(scsi_qla_host_t *); | extern int qla2x00_fdmi_register(scsi_qla_host_t *); | ||||||
| extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); | extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); | ||||||
| extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); |  | ||||||
| extern size_t qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); | extern size_t qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); | ||||||
| extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *, | extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *, | ||||||
| 	struct ct_sns_rsp *, const char *); | 	struct ct_sns_rsp *, const char *); | ||||||
|  | @ -822,7 +819,6 @@ extern int qlafx00_rescan_isp(scsi_qla_host_t *); | ||||||
| /* PCI related functions */ | /* PCI related functions */ | ||||||
| extern int qla82xx_pci_config(struct scsi_qla_host *); | extern int qla82xx_pci_config(struct scsi_qla_host *); | ||||||
| extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int); | extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int); | ||||||
| extern int qla82xx_pci_region_offset(struct pci_dev *, int); |  | ||||||
| extern int qla82xx_iospace_config(struct qla_hw_data *); | extern int qla82xx_iospace_config(struct qla_hw_data *); | ||||||
| 
 | 
 | ||||||
| /* Initialization related functions */ | /* Initialization related functions */ | ||||||
|  | @ -866,7 +862,6 @@ extern int qla82xx_rd_32(struct qla_hw_data *, ulong); | ||||||
| 
 | 
 | ||||||
| /* ISP 8021 IDC */ | /* ISP 8021 IDC */ | ||||||
| extern void qla82xx_clear_drv_active(struct qla_hw_data *); | extern void qla82xx_clear_drv_active(struct qla_hw_data *); | ||||||
| extern uint32_t  qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t); |  | ||||||
| extern int qla82xx_idc_lock(struct qla_hw_data *); | extern int qla82xx_idc_lock(struct qla_hw_data *); | ||||||
| extern void qla82xx_idc_unlock(struct qla_hw_data *); | extern void qla82xx_idc_unlock(struct qla_hw_data *); | ||||||
| extern int qla82xx_device_state_handler(scsi_qla_host_t *); | extern int qla82xx_device_state_handler(scsi_qla_host_t *); | ||||||
|  |  | ||||||
|  | @ -2625,96 +2625,6 @@ qla2x00_port_speed_capability(uint16_t speed) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. |  | ||||||
|  * @vha: HA context |  | ||||||
|  * @list: switch info entries to populate |  | ||||||
|  * |  | ||||||
|  * Returns 0 on success. |  | ||||||
|  */ |  | ||||||
| int |  | ||||||
| qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) |  | ||||||
| { |  | ||||||
| 	int		rval; |  | ||||||
| 	uint16_t	i; |  | ||||||
| 	struct qla_hw_data *ha = vha->hw; |  | ||||||
| 	ms_iocb_entry_t *ms_pkt; |  | ||||||
| 	struct ct_sns_req	*ct_req; |  | ||||||
| 	struct ct_sns_rsp	*ct_rsp; |  | ||||||
| 	struct ct_arg arg; |  | ||||||
| 
 |  | ||||||
| 	if (!IS_IIDMA_CAPABLE(ha)) |  | ||||||
| 		return QLA_FUNCTION_FAILED; |  | ||||||
| 	if (!ha->flags.gpsc_supported) |  | ||||||
| 		return QLA_FUNCTION_FAILED; |  | ||||||
| 
 |  | ||||||
| 	rval = qla2x00_mgmt_svr_login(vha); |  | ||||||
| 	if (rval) |  | ||||||
| 		return rval; |  | ||||||
| 
 |  | ||||||
| 	arg.iocb = ha->ms_iocb; |  | ||||||
| 	arg.req_dma = ha->ct_sns_dma; |  | ||||||
| 	arg.rsp_dma = ha->ct_sns_dma; |  | ||||||
| 	arg.req_size = GPSC_REQ_SIZE; |  | ||||||
| 	arg.rsp_size = GPSC_RSP_SIZE; |  | ||||||
| 	arg.nport_handle = vha->mgmt_svr_loop_id; |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < ha->max_fibre_devices; i++) { |  | ||||||
| 		/* Issue GFPN_ID */ |  | ||||||
| 		/* Prepare common MS IOCB */ |  | ||||||
| 		ms_pkt = qla24xx_prep_ms_iocb(vha, &arg); |  | ||||||
| 
 |  | ||||||
| 		/* Prepare CT request */ |  | ||||||
| 		ct_req = qla24xx_prep_ct_fm_req(ha->ct_sns, GPSC_CMD, |  | ||||||
| 		    GPSC_RSP_SIZE); |  | ||||||
| 		ct_rsp = &ha->ct_sns->p.rsp; |  | ||||||
| 
 |  | ||||||
| 		/* Prepare CT arguments -- port_name */ |  | ||||||
| 		memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name, |  | ||||||
| 		    WWN_SIZE); |  | ||||||
| 
 |  | ||||||
| 		/* Execute MS IOCB */ |  | ||||||
| 		rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, |  | ||||||
| 		    sizeof(ms_iocb_entry_t)); |  | ||||||
| 		if (rval != QLA_SUCCESS) { |  | ||||||
| 			/*EMPTY*/ |  | ||||||
| 			ql_dbg(ql_dbg_disc, vha, 0x2059, |  | ||||||
| 			    "GPSC issue IOCB failed (%d).\n", rval); |  | ||||||
| 		} else if ((rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, |  | ||||||
| 		    "GPSC")) != QLA_SUCCESS) { |  | ||||||
| 			/* FM command unsupported? */ |  | ||||||
| 			if (rval == QLA_INVALID_COMMAND && |  | ||||||
| 			    (ct_rsp->header.reason_code == |  | ||||||
| 				CT_REASON_INVALID_COMMAND_CODE || |  | ||||||
| 			     ct_rsp->header.reason_code == |  | ||||||
| 				CT_REASON_COMMAND_UNSUPPORTED)) { |  | ||||||
| 				ql_dbg(ql_dbg_disc, vha, 0x205a, |  | ||||||
| 				    "GPSC command unsupported, disabling " |  | ||||||
| 				    "query.\n"); |  | ||||||
| 				ha->flags.gpsc_supported = 0; |  | ||||||
| 				rval = QLA_FUNCTION_FAILED; |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 			rval = QLA_FUNCTION_FAILED; |  | ||||||
| 		} else { |  | ||||||
| 			list->fp_speed = qla2x00_port_speed_capability( |  | ||||||
| 			    be16_to_cpu(ct_rsp->rsp.gpsc.speed)); |  | ||||||
| 			ql_dbg(ql_dbg_disc, vha, 0x205b, |  | ||||||
| 			    "GPSC ext entry - fpn " |  | ||||||
| 			    "%8phN speeds=%04x speed=%04x.\n", |  | ||||||
| 			    list[i].fabric_port_name, |  | ||||||
| 			    be16_to_cpu(ct_rsp->rsp.gpsc.speeds), |  | ||||||
| 			    be16_to_cpu(ct_rsp->rsp.gpsc.speed)); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* Last device exit. */ |  | ||||||
| 		if (list[i].d_id.b.rsvd_1 != 0) |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return (rval); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query. |  * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query. | ||||||
|  * |  * | ||||||
|  |  | ||||||
|  | @ -1099,11 +1099,6 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) | ||||||
| 	unsigned offset, n; | 	unsigned offset, n; | ||||||
| 	struct qla_hw_data *ha = vha->hw; | 	struct qla_hw_data *ha = vha->hw; | ||||||
| 
 | 
 | ||||||
| 	struct crb_addr_pair { |  | ||||||
| 		long addr; |  | ||||||
| 		long data; |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	/* Halt all the individual PEGs and other blocks of the ISP */ | 	/* Halt all the individual PEGs and other blocks of the ISP */ | ||||||
| 	qla82xx_rom_lock(ha); | 	qla82xx_rom_lock(ha); | ||||||
| 
 | 
 | ||||||
|  | @ -1595,25 +1590,6 @@ qla82xx_get_fw_offs(struct qla_hw_data *ha) | ||||||
| 	return (u8 *)&ha->hablob->fw->data[offset]; | 	return (u8 *)&ha->hablob->fw->data[offset]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* PCI related functions */ |  | ||||||
| int qla82xx_pci_region_offset(struct pci_dev *pdev, int region) |  | ||||||
| { |  | ||||||
| 	unsigned long val = 0; |  | ||||||
| 	u32 control; |  | ||||||
| 
 |  | ||||||
| 	switch (region) { |  | ||||||
| 	case 0: |  | ||||||
| 		val = 0; |  | ||||||
| 		break; |  | ||||||
| 	case 1: |  | ||||||
| 		pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control); |  | ||||||
| 		val = control + QLA82XX_MSIX_TBL_SPACE; |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 	return val; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| int | int | ||||||
| qla82xx_iospace_config(struct qla_hw_data *ha) | qla82xx_iospace_config(struct qla_hw_data *ha) | ||||||
| { | { | ||||||
|  | @ -2934,32 +2910,6 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
| * qla82xx_wait_for_state_change |  | ||||||
| *    Wait for device state to change from given current state |  | ||||||
| * |  | ||||||
| * Note: |  | ||||||
| *     IDC lock must not be held upon entry |  | ||||||
| * |  | ||||||
| * Return: |  | ||||||
| *    Changed device state. |  | ||||||
| */ |  | ||||||
| uint32_t |  | ||||||
| qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state) |  | ||||||
| { |  | ||||||
| 	struct qla_hw_data *ha = vha->hw; |  | ||||||
| 	uint32_t dev_state; |  | ||||||
| 
 |  | ||||||
| 	do { |  | ||||||
| 		msleep(1000); |  | ||||||
| 		qla82xx_idc_lock(ha); |  | ||||||
| 		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); |  | ||||||
| 		qla82xx_idc_unlock(ha); |  | ||||||
| 	} while (dev_state == curr_state); |  | ||||||
| 
 |  | ||||||
| 	return dev_state; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void | void | ||||||
| qla8xxx_dev_failed_handler(scsi_qla_host_t *vha) | qla8xxx_dev_failed_handler(scsi_qla_host_t *vha) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -176,12 +176,6 @@ MODULE_PARM_DESC(ql2xenablehba_err_chk, | ||||||
| 		"  1 -- Error isolation enabled only for DIX Type 0\n" | 		"  1 -- Error isolation enabled only for DIX Type 0\n" | ||||||
| 		"  2 -- Error isolation enabled for all Types\n"); | 		"  2 -- Error isolation enabled for all Types\n"); | ||||||
| 
 | 
 | ||||||
| int ql2xiidmaenable = 1; |  | ||||||
| module_param(ql2xiidmaenable, int, S_IRUGO); |  | ||||||
| MODULE_PARM_DESC(ql2xiidmaenable, |  | ||||||
| 		"Enables iIDMA settings " |  | ||||||
| 		"Default is 1 - perform iIDMA. 0 - no iIDMA."); |  | ||||||
| 
 |  | ||||||
| int ql2xmqsupport = 1; | int ql2xmqsupport = 1; | ||||||
| module_param(ql2xmqsupport, int, S_IRUGO); | module_param(ql2xmqsupport, int, S_IRUGO); | ||||||
| MODULE_PARM_DESC(ql2xmqsupport, | MODULE_PARM_DESC(ql2xmqsupport, | ||||||
|  | @ -199,12 +193,6 @@ MODULE_PARM_DESC(ql2xfwloadbin, | ||||||
| 		" 1 -- load firmware from flash.\n" | 		" 1 -- load firmware from flash.\n" | ||||||
| 		" 0 -- use default semantics.\n"); | 		" 0 -- use default semantics.\n"); | ||||||
| 
 | 
 | ||||||
| int ql2xetsenable; |  | ||||||
| module_param(ql2xetsenable, int, S_IRUGO); |  | ||||||
| MODULE_PARM_DESC(ql2xetsenable, |  | ||||||
| 		"Enables firmware ETS burst." |  | ||||||
| 		"Default is 0 - skip ETS enablement."); |  | ||||||
| 
 |  | ||||||
| int ql2xdbwr = 1; | int ql2xdbwr = 1; | ||||||
| module_param(ql2xdbwr, int, S_IRUGO|S_IWUSR); | module_param(ql2xdbwr, int, S_IRUGO|S_IWUSR); | ||||||
| MODULE_PARM_DESC(ql2xdbwr, | MODULE_PARM_DESC(ql2xdbwr, | ||||||
|  |  | ||||||
|  | @ -1454,50 +1454,6 @@ static struct fc_port *qlt_create_sess( | ||||||
| 	return sess; | 	return sess; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * max_gen - specifies maximum session generation |  | ||||||
|  * at which this deletion requestion is still valid |  | ||||||
|  */ |  | ||||||
| void |  | ||||||
| qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen) |  | ||||||
| { |  | ||||||
| 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; |  | ||||||
| 	struct fc_port *sess = fcport; |  | ||||||
| 	unsigned long flags; |  | ||||||
| 
 |  | ||||||
| 	if (!vha->hw->tgt.tgt_ops) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	if (!tgt) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); |  | ||||||
| 	if (tgt->tgt_stop) { |  | ||||||
| 		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	if (!sess->se_sess) { |  | ||||||
| 		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (max_gen - sess->generation < 0) { |  | ||||||
| 		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); |  | ||||||
| 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092, |  | ||||||
| 		    "Ignoring stale deletion request for se_sess %p / sess %p" |  | ||||||
| 		    " for port %8phC, req_gen %d, sess_gen %d\n", |  | ||||||
| 		    sess->se_sess, sess, sess->port_name, max_gen, |  | ||||||
| 		    sess->generation); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); |  | ||||||
| 
 |  | ||||||
| 	sess->local = 1; |  | ||||||
| 	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); |  | ||||||
| 	qlt_schedule_sess_for_deletion(sess); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int test_tgt_sess_count(struct qla_tgt *tgt) | static inline int test_tgt_sess_count(struct qla_tgt *tgt) | ||||||
| { | { | ||||||
| 	struct qla_hw_data *ha = tgt->ha; | 	struct qla_hw_data *ha = tgt->ha; | ||||||
|  | @ -5539,81 +5495,6 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, | ||||||
| 	spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); | 	spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int |  | ||||||
| qlt_free_qfull_cmds(struct qla_qpair *qpair) |  | ||||||
| { |  | ||||||
| 	struct scsi_qla_host *vha = qpair->vha; |  | ||||||
| 	struct qla_hw_data *ha = vha->hw; |  | ||||||
| 	unsigned long flags; |  | ||||||
| 	struct qla_tgt_cmd *cmd, *tcmd; |  | ||||||
| 	struct list_head free_list, q_full_list; |  | ||||||
| 	int rc = 0; |  | ||||||
| 
 |  | ||||||
| 	if (list_empty(&ha->tgt.q_full_list)) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	INIT_LIST_HEAD(&free_list); |  | ||||||
| 	INIT_LIST_HEAD(&q_full_list); |  | ||||||
| 
 |  | ||||||
| 	spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); |  | ||||||
| 	if (list_empty(&ha->tgt.q_full_list)) { |  | ||||||
| 		spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	list_splice_init(&vha->hw->tgt.q_full_list, &q_full_list); |  | ||||||
| 	spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); |  | ||||||
| 
 |  | ||||||
| 	spin_lock_irqsave(qpair->qp_lock_ptr, flags); |  | ||||||
| 	list_for_each_entry_safe(cmd, tcmd, &q_full_list, cmd_list) { |  | ||||||
| 		if (cmd->q_full) |  | ||||||
| 			/* cmd->state is a borrowed field to hold status */ |  | ||||||
| 			rc = __qlt_send_busy(qpair, &cmd->atio, cmd->state); |  | ||||||
| 		else if (cmd->term_exchg) |  | ||||||
| 			rc = __qlt_send_term_exchange(qpair, NULL, &cmd->atio); |  | ||||||
| 
 |  | ||||||
| 		if (rc == -ENOMEM) |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 		if (cmd->q_full) |  | ||||||
| 			ql_dbg(ql_dbg_io, vha, 0x3006, |  | ||||||
| 			    "%s: busy sent for ox_id[%04x]\n", __func__, |  | ||||||
| 			    be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id)); |  | ||||||
| 		else if (cmd->term_exchg) |  | ||||||
| 			ql_dbg(ql_dbg_io, vha, 0x3007, |  | ||||||
| 			    "%s: Term exchg sent for ox_id[%04x]\n", __func__, |  | ||||||
| 			    be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id)); |  | ||||||
| 		else |  | ||||||
| 			ql_dbg(ql_dbg_io, vha, 0x3008, |  | ||||||
| 			    "%s: Unexpected cmd in QFull list %p\n", __func__, |  | ||||||
| 			    cmd); |  | ||||||
| 
 |  | ||||||
| 		list_move_tail(&cmd->cmd_list, &free_list); |  | ||||||
| 
 |  | ||||||
| 		/* piggy back on hardware_lock for protection */ |  | ||||||
| 		vha->hw->tgt.num_qfull_cmds_alloc--; |  | ||||||
| 	} |  | ||||||
| 	spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); |  | ||||||
| 
 |  | ||||||
| 	cmd = NULL; |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry_safe(cmd, tcmd, &free_list, cmd_list) { |  | ||||||
| 		list_del(&cmd->cmd_list); |  | ||||||
| 		/* This cmd was never sent to TCM.  There is no need
 |  | ||||||
| 		 * to schedule free or call free_cmd |  | ||||||
| 		 */ |  | ||||||
| 		qlt_free_cmd(cmd); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (!list_empty(&q_full_list)) { |  | ||||||
| 		spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags); |  | ||||||
| 		list_splice(&q_full_list, &vha->hw->tgt.q_full_list); |  | ||||||
| 		spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void | static void | ||||||
| qlt_send_busy(struct qla_qpair *qpair, struct atio_from_isp *atio, | qlt_send_busy(struct qla_qpair *qpair, struct atio_from_isp *atio, | ||||||
|     uint16_t status) |     uint16_t status) | ||||||
|  | @ -7090,16 +6971,6 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void |  | ||||||
| qlt_83xx_iospace_config(struct qla_hw_data *ha) |  | ||||||
| { |  | ||||||
| 	if (!QLA_TGT_MODE_ENABLED()) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	ha->msix_count += 1; /* For ATIO Q */ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void | void | ||||||
| qlt_modify_vp_config(struct scsi_qla_host *vha, | qlt_modify_vp_config(struct scsi_qla_host *vha, | ||||||
| 	struct vp_config_entry_24xx *vpmod) | 	struct vp_config_entry_24xx *vpmod) | ||||||
|  |  | ||||||
|  | @ -1014,7 +1014,6 @@ extern int qlt_lport_register(void *, u64, u64, u64, | ||||||
| extern void qlt_lport_deregister(struct scsi_qla_host *); | extern void qlt_lport_deregister(struct scsi_qla_host *); | ||||||
| extern void qlt_unreg_sess(struct fc_port *); | extern void qlt_unreg_sess(struct fc_port *); | ||||||
| extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *); | extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *); | ||||||
| extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int); |  | ||||||
| extern int __init qlt_init(void); | extern int __init qlt_init(void); | ||||||
| extern void qlt_exit(void); | extern void qlt_exit(void); | ||||||
| extern void qlt_free_session_done(struct work_struct *); | extern void qlt_free_session_done(struct work_struct *); | ||||||
|  | @ -1082,8 +1081,6 @@ extern void qlt_mem_free(struct qla_hw_data *); | ||||||
| extern int qlt_stop_phase1(struct qla_tgt *); | extern int qlt_stop_phase1(struct qla_tgt *); | ||||||
| extern void qlt_stop_phase2(struct qla_tgt *); | extern void qlt_stop_phase2(struct qla_tgt *); | ||||||
| extern irqreturn_t qla83xx_msix_atio_q(int, void *); | extern irqreturn_t qla83xx_msix_atio_q(int, void *); | ||||||
| extern void qlt_83xx_iospace_config(struct qla_hw_data *); |  | ||||||
| extern int qlt_free_qfull_cmds(struct qla_qpair *); |  | ||||||
| extern void qlt_logo_completion_handler(fc_port_t *, int); | extern void qlt_logo_completion_handler(fc_port_t *, int); | ||||||
| extern void qlt_do_generation_tick(struct scsi_qla_host *, int *); | extern void qlt_do_generation_tick(struct scsi_qla_host *, int *); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -973,11 +973,6 @@ qla4_82xx_pinit_from_rom(struct scsi_qla_host *ha, int verbose) | ||||||
| 	unsigned long off; | 	unsigned long off; | ||||||
| 	unsigned offset, n; | 	unsigned offset, n; | ||||||
| 
 | 
 | ||||||
| 	struct crb_addr_pair { |  | ||||||
| 		long addr; |  | ||||||
| 		long data; |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	/* Halt all the indiviual PEGs and other blocks of the ISP */ | 	/* Halt all the indiviual PEGs and other blocks of the ISP */ | ||||||
| 	qla4_82xx_rom_lock(ha); | 	qla4_82xx_rom_lock(ha); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -162,7 +162,7 @@ static const char *sdebug_version_date = "20210520"; | ||||||
| #define DEF_VPD_USE_HOSTNO 1 | #define DEF_VPD_USE_HOSTNO 1 | ||||||
| #define DEF_WRITESAME_LENGTH 0xFFFF | #define DEF_WRITESAME_LENGTH 0xFFFF | ||||||
| #define DEF_ATOMIC_WR 0 | #define DEF_ATOMIC_WR 0 | ||||||
| #define DEF_ATOMIC_WR_MAX_LENGTH 8192 | #define DEF_ATOMIC_WR_MAX_LENGTH 128 | ||||||
| #define DEF_ATOMIC_WR_ALIGN 2 | #define DEF_ATOMIC_WR_ALIGN 2 | ||||||
| #define DEF_ATOMIC_WR_GRAN 2 | #define DEF_ATOMIC_WR_GRAN 2 | ||||||
| #define DEF_ATOMIC_WR_MAX_LENGTH_BNDRY (DEF_ATOMIC_WR_MAX_LENGTH) | #define DEF_ATOMIC_WR_MAX_LENGTH_BNDRY (DEF_ATOMIC_WR_MAX_LENGTH) | ||||||
|  | @ -294,6 +294,14 @@ struct tape_block { | ||||||
| #define FF_SA (F_SA_HIGH | F_SA_LOW) | #define FF_SA (F_SA_HIGH | F_SA_LOW) | ||||||
| #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY) | #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY) | ||||||
| 
 | 
 | ||||||
|  | /* Device selection bit mask */ | ||||||
|  | #define DS_ALL     0xffffffff | ||||||
|  | #define DS_SBC     (1 << TYPE_DISK) | ||||||
|  | #define DS_SSC     (1 << TYPE_TAPE) | ||||||
|  | #define DS_ZBC     (1 << TYPE_ZBC) | ||||||
|  | 
 | ||||||
|  | #define DS_NO_SSC  (DS_ALL & ~DS_SSC) | ||||||
|  | 
 | ||||||
| #define SDEBUG_MAX_PARTS 4 | #define SDEBUG_MAX_PARTS 4 | ||||||
| 
 | 
 | ||||||
| #define SDEBUG_MAX_CMD_LEN 32 | #define SDEBUG_MAX_CMD_LEN 32 | ||||||
|  | @ -472,6 +480,7 @@ struct opcode_info_t { | ||||||
| 				/* for terminating element */ | 				/* for terminating element */ | ||||||
| 	u8 opcode;		/* if num_attached > 0, preferred */ | 	u8 opcode;		/* if num_attached > 0, preferred */ | ||||||
| 	u16 sa;			/* service action */ | 	u16 sa;			/* service action */ | ||||||
|  | 	u32 devsel;		/* device type mask for this definition */ | ||||||
| 	u32 flags;		/* OR-ed set of SDEB_F_* */ | 	u32 flags;		/* OR-ed set of SDEB_F_* */ | ||||||
| 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); | 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */ | 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */ | ||||||
|  | @ -519,7 +528,8 @@ enum sdeb_opcode_index { | ||||||
| 	SDEB_I_WRITE_FILEMARKS = 35, | 	SDEB_I_WRITE_FILEMARKS = 35, | ||||||
| 	SDEB_I_SPACE = 36, | 	SDEB_I_SPACE = 36, | ||||||
| 	SDEB_I_FORMAT_MEDIUM = 37, | 	SDEB_I_FORMAT_MEDIUM = 37, | ||||||
| 	SDEB_I_LAST_ELEM_P1 = 38,	/* keep this last (previous + 1) */ | 	SDEB_I_ERASE = 38, | ||||||
|  | 	SDEB_I_LAST_ELEM_P1 = 39,	/* keep this last (previous + 1) */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -530,7 +540,7 @@ static const unsigned char opcode_ind_arr[256] = { | ||||||
| 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, | 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, | ||||||
| 	SDEB_I_WRITE_FILEMARKS, SDEB_I_SPACE, SDEB_I_INQUIRY, 0, 0, | 	SDEB_I_WRITE_FILEMARKS, SDEB_I_SPACE, SDEB_I_INQUIRY, 0, 0, | ||||||
| 	    SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE, | 	    SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE, | ||||||
| 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, | 	0, SDEB_I_ERASE, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, | ||||||
| 	    SDEB_I_ALLOW_REMOVAL, 0, | 	    SDEB_I_ALLOW_REMOVAL, 0, | ||||||
| /* 0x20; 0x20->0x3f: 10 byte cdbs */ | /* 0x20; 0x20->0x3f: 10 byte cdbs */ | ||||||
| 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, | 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, | ||||||
|  | @ -585,7 +595,9 @@ static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
|  | static int resp_read_tape(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
|  | static int resp_write_tape(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
|  | @ -613,8 +625,10 @@ static int resp_read_blklimits(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_locate(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_locate(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_space(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_space(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
|  | static int resp_read_position(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_rewind(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_rewind(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| static int resp_format_medium(struct scsi_cmnd *, struct sdebug_dev_info *); | static int resp_format_medium(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
|  | static int resp_erase(struct scsi_cmnd *, struct sdebug_dev_info *); | ||||||
| 
 | 
 | ||||||
| static int sdebug_do_add_host(bool mk_new_store); | static int sdebug_do_add_host(bool mk_new_store); | ||||||
| static int sdebug_add_host_helper(int per_host_idx); | static int sdebug_add_host_helper(int per_host_idx); | ||||||
|  | @ -629,113 +643,121 @@ static void sdebug_erase_all_stores(bool apart_from_first); | ||||||
|  * should be placed in opcode_info_arr[], the others should be placed here. |  * should be placed in opcode_info_arr[], the others should be placed here. | ||||||
|  */ |  */ | ||||||
| static const struct opcode_info_t msense_iarr[] = { | static const struct opcode_info_t msense_iarr[] = { | ||||||
| 	{0, 0x1a, 0, F_D_IN, NULL, NULL, | 	{0, 0x1a, 0, DS_ALL, F_D_IN, NULL, NULL, | ||||||
| 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t mselect_iarr[] = { | static const struct opcode_info_t mselect_iarr[] = { | ||||||
| 	{0, 0x15, 0, F_D_OUT, NULL, NULL, | 	{0, 0x15, 0, DS_ALL, F_D_OUT, NULL, NULL, | ||||||
| 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t read_iarr[] = { | static const struct opcode_info_t read_iarr[] = { | ||||||
| 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ | 	{0, 0x28, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ | ||||||
| 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, | 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, | ||||||
| 	     0, 0, 0, 0} }, | 	     0, 0, 0, 0} }, | ||||||
| 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ | 	{0, 0x8, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) disk */ | ||||||
| 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ | 	{0, 0x8, 0, DS_SSC, F_D_IN | FF_MEDIA_IO, resp_read_tape, NULL, /* READ(6) tape */ | ||||||
|  | 	    {6,  0x03, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
|  | 	{0, 0xa8, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ | ||||||
| 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, | 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, | ||||||
| 	     0xc7, 0, 0, 0, 0} }, | 	     0xc7, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t write_iarr[] = { | static const struct opcode_info_t write_iarr[] = { | ||||||
| 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */ | 	{0, 0x2a, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */ | ||||||
| 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, | 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, | ||||||
| 		   0, 0, 0, 0, 0, 0} }, | 		   0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */ | 	{0, 0xa, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) disk */ | ||||||
| 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, | 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 		   0, 0, 0} }, | 		   0, 0, 0} }, | ||||||
| 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */ | 	{0, 0xa, 0, DS_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_tape, /* WRITE(6) tape */ | ||||||
|  | 	    NULL, {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 		   0, 0, 0} }, | ||||||
|  | 	{0, 0xaa, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */ | ||||||
| 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 		   0xbf, 0xc7, 0, 0, 0, 0} }, | 		   0xbf, 0xc7, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t verify_iarr[] = { | static const struct opcode_info_t verify_iarr[] = { | ||||||
| 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ | 	{0, 0x2f, 0, DS_NO_SSC, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ | ||||||
| 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, | 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, | ||||||
| 		   0, 0, 0, 0, 0, 0} }, | 		   0, 0, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t sa_in_16_iarr[] = { | static const struct opcode_info_t sa_in_16_iarr[] = { | ||||||
| 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, | 	{0, 0x9e, 0x12, DS_NO_SSC, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, | ||||||
| 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */ | 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */ | ||||||
| 	{0, 0x9e, 0x16, F_SA_LOW | F_D_IN, resp_get_stream_status, NULL, | 	{0, 0x9e, 0x16, DS_NO_SSC, F_SA_LOW | F_D_IN, resp_get_stream_status, NULL, | ||||||
| 	    {16, 0x16, 0, 0, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, | 	    {16, 0x16, 0, 0, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0, 0} },	/* GET STREAM STATUS */ | 	     0, 0} },	/* GET STREAM STATUS */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */ | static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */ | ||||||
| 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, | 	{0, 0x7f, 0xb, DS_NO_SSC, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, | ||||||
| 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, | 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, | ||||||
| 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */ | 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */ | ||||||
| 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, | 	{0, 0x7f, 0x11, DS_NO_SSC, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, | ||||||
| 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, | 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, | ||||||
| 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */ | 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */ | static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */ | ||||||
| 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, | 	{0, 0xa3, 0xc, DS_ALL, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, | ||||||
| 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, | 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, | ||||||
| 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ | 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ | ||||||
| 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, | 	{0, 0xa3, 0xd, DS_ALL, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, | ||||||
| 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, | 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, | ||||||
| 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ | 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t write_same_iarr[] = { | static const struct opcode_info_t write_same_iarr[] = { | ||||||
| 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, | 	{0, 0x93, 0, DS_NO_SSC, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, | ||||||
| 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */ | 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t reserve_iarr[] = { | static const struct opcode_info_t reserve_iarr[] = { | ||||||
| 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */ | 	{0, 0x16, 0, DS_ALL, F_D_OUT, NULL, NULL,	/* RESERVE(6) */ | ||||||
| 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t release_iarr[] = { | static const struct opcode_info_t release_iarr[] = { | ||||||
| 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */ | 	{0, 0x17, 0, DS_ALL, F_D_OUT, NULL, NULL,	/* RELEASE(6) */ | ||||||
| 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t sync_cache_iarr[] = { | static const struct opcode_info_t sync_cache_iarr[] = { | ||||||
| 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, | 	{0, 0x91, 0, DS_NO_SSC, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, | ||||||
| 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */ | 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t pre_fetch_iarr[] = { | static const struct opcode_info_t pre_fetch_iarr[] = { | ||||||
| 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, | 	{0, 0x90, 0, DS_NO_SSC, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, | ||||||
| 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */ | 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */ | ||||||
|  | 	{0, 0x34, 0, DS_SSC, F_SYNC_DELAY | FF_MEDIA_IO, resp_read_position, NULL, | ||||||
|  | 	    {10,  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc7, 0, 0, | ||||||
|  | 	     0, 0, 0, 0} },				/* READ POSITION (10) */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */ | static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */ | ||||||
| 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, | 	{0, 0x94, 0x1, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, | ||||||
| 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */ | 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */ | ||||||
| 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, | 	{0, 0x94, 0x2, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, | ||||||
| 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */ | 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */ | ||||||
| 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, | 	{0, 0x94, 0x4, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, | ||||||
| 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */ | 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */ | static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */ | ||||||
| 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, | 	{0, 0x95, 0x6, DS_NO_SSC, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, | ||||||
| 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ | 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ | ||||||
| }; | }; | ||||||
|  | @ -746,130 +768,132 @@ static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */ | ||||||
|  * REPORT SUPPORTED OPERATION CODES. */ |  * REPORT SUPPORTED OPERATION CODES. */ | ||||||
| static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { | static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { | ||||||
| /* 0 */ | /* 0 */ | ||||||
| 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */ | 	{0, 0, 0, DS_ALL, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */ | ||||||
| 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ | 	{0, 0x12, 0, DS_ALL, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ | ||||||
| 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, | 	{0, 0xa0, 0, DS_ALL, FF_RESPOND | F_D_IN, resp_report_luns, NULL, | ||||||
| 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, | 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, | ||||||
| 	     0, 0} },					/* REPORT LUNS */ | 	     0, 0} },					/* REPORT LUNS */ | ||||||
| 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, | 	{0, 0x3, 0, DS_ALL, FF_RESPOND | F_D_IN, resp_requests, NULL, | ||||||
| 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ | 	{0, 0x0, 0, DS_ALL, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ | ||||||
| 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| /* 5 */ | /* 5 */ | ||||||
| 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */ | 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, DS_ALL, F_D_IN,	/* MODE SENSE(10) */ | ||||||
| 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0, | 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0, | ||||||
| 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, | 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */ | 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, DS_ALL, F_D_OUT,	/* MODE SELECT(10) */ | ||||||
| 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff, | 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff, | ||||||
| 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, | 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */ | 	{0, 0x4d, 0, DS_NO_SSC, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */ | ||||||
| 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, | 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, | ||||||
| 	     0, 0, 0} }, | 	     0, 0, 0} }, | ||||||
| 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */ | 	{0, 0x25, 0, DS_NO_SSC, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */ | ||||||
| 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, | 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, | ||||||
| 	     0, 0} }, | 	     0, 0} }, | ||||||
| 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ | 	{ARRAY_SIZE(read_iarr), 0x88, 0, DS_NO_SSC, F_D_IN | FF_MEDIA_IO, /* READ(16) */ | ||||||
| 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff, | 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff, | ||||||
| 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, | 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, | ||||||
| /* 10 */ | /* 10 */ | ||||||
| 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, | 	{ARRAY_SIZE(write_iarr), 0x8a, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, | ||||||
| 	    resp_write_dt0, write_iarr,			/* WRITE(16) */ | 	    resp_write_dt0, write_iarr,			/* WRITE(16) */ | ||||||
| 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, | 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, | ||||||
| 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ | 	{0, 0x1b, 0, DS_ALL, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ | ||||||
| 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, | 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, DS_NO_SSC, F_SA_LOW | F_D_IN, | ||||||
| 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ | 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ | ||||||
| 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, | 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, | ||||||
| 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, | 	{0, 0x9f, 0x12, DS_NO_SSC, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, | ||||||
| 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, | 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, | ||||||
| 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */ | 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */ | ||||||
| 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, | 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, DS_ALL, F_SA_LOW | F_D_IN, | ||||||
| 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */ | 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */ | ||||||
| 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, | 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, | ||||||
| 				0xff, 0, 0xc7, 0, 0, 0, 0} }, | 				0xff, 0, 0xc7, 0, 0, 0, 0} }, | ||||||
| /* 15 */ | /* 15 */ | ||||||
| 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ | 	{0, 0, 0, DS_ALL, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ | ||||||
| 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{ARRAY_SIZE(verify_iarr), 0x8f, 0, | 	{ARRAY_SIZE(verify_iarr), 0x8f, 0, DS_NO_SSC, | ||||||
| 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */ | 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */ | ||||||
| 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, | 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, | ||||||
| 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, | 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, DS_NO_SSC, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, | ||||||
| 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */ | 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */ | ||||||
| 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, | 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, | ||||||
| 	     0xff, 0xff} }, | 	     0xff, 0xff} }, | ||||||
| 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, | 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, DS_ALL, F_D_OUT, | ||||||
| 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */ | 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */ | ||||||
| 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, | 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, | ||||||
| 	     0} }, | 	     0} }, | ||||||
| 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, | 	{ARRAY_SIZE(release_iarr), 0x57, 0, DS_ALL, F_D_OUT, | ||||||
| 	    NULL, release_iarr, /* RELEASE(10) <no response function> */ | 	    NULL, release_iarr, /* RELEASE(10) <no response function> */ | ||||||
| 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, | 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, | ||||||
| 	     0} }, | 	     0} }, | ||||||
| /* 20 */ | /* 20 */ | ||||||
| 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ | 	{0, 0x1e, 0, DS_ALL, 0, NULL, NULL, /* ALLOW REMOVAL */ | ||||||
| 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x1, 0, 0, resp_rewind, NULL, | 	{0, 0x1, 0, DS_SSC, 0, resp_rewind, NULL, | ||||||
| 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ | 	{0, 0, 0, DS_NO_SSC, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ | ||||||
| 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */ | 	{0, 0x1d, 0, DS_ALL, F_D_OUT, NULL, NULL,      /* SEND DIAGNOSTIC */ | ||||||
| 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ | 	{0, 0x42, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ | ||||||
| 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, | 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, | ||||||
| /* 25 */ | /* 25 */ | ||||||
| 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, | 	{0, 0x3b, 0, DS_NO_SSC, F_D_OUT_MAYBE, resp_write_buffer, NULL, | ||||||
| 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, | 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, | ||||||
| 	     0, 0, 0, 0} },			/* WRITE_BUFFER */ | 	     0, 0, 0, 0} },			/* WRITE_BUFFER */ | ||||||
| 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, | 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, DS_NO_SSC, F_D_OUT_MAYBE | FF_MEDIA_IO, | ||||||
| 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */ | 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */ | ||||||
| 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, | 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, | ||||||
| 		 0, 0, 0, 0, 0} }, | 		 0, 0, 0, 0, 0} }, | ||||||
| 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, | 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, DS_NO_SSC, F_SYNC_DELAY | F_M_ACCESS, | ||||||
| 	    resp_sync_cache, sync_cache_iarr, | 	    resp_sync_cache, sync_cache_iarr, | ||||||
| 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, | 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, | ||||||
| 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */ | 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */ | ||||||
| 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, | 	{0, 0x89, 0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, | ||||||
| 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, | 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, | ||||||
| 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */ | 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */ | ||||||
| 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, | 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, DS_NO_SSC, F_SYNC_DELAY | FF_MEDIA_IO, | ||||||
| 	    resp_pre_fetch, pre_fetch_iarr, | 	    resp_pre_fetch, pre_fetch_iarr, | ||||||
| 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, | 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, | ||||||
| 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */ | 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */ | ||||||
| 						/* READ POSITION (10) */ | 						/* READ POSITION (10) */ | ||||||
| 
 | 
 | ||||||
| /* 30 */ | /* 30 */ | ||||||
| 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, | 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, | ||||||
| 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ | 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ | ||||||
| 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, | 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, | ||||||
| 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, | 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, DS_NO_SSC, F_SA_LOW | F_M_ACCESS, | ||||||
| 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ | 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ | ||||||
| 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, | 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, | ||||||
| /* 32 */ | /* 32 */ | ||||||
| 	{0, 0x0, 0x0, F_D_OUT | FF_MEDIA_IO, | 	{0, 0x9c, 0x0, DS_NO_SSC, F_D_OUT | FF_MEDIA_IO, | ||||||
| 	    resp_atomic_write, NULL, /* ATOMIC WRITE 16 */ | 	    resp_atomic_write, NULL, /* ATOMIC WRITE 16 */ | ||||||
| 		{16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 		{16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||||||
| 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }, | 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }, | ||||||
| 	{0, 0x05, 0, F_D_IN, resp_read_blklimits, NULL,    /* READ BLOCK LIMITS (6) */ | 	{0, 0x05, 0, DS_SSC, F_D_IN, resp_read_blklimits, NULL,    /* READ BLOCK LIMITS (6) */ | ||||||
| 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x2b, 0, F_D_UNKN, resp_locate, NULL,    /* LOCATE (10) */ | 	{0, 0x2b, 0, DS_SSC, F_D_UNKN, resp_locate, NULL,	   /* LOCATE (10) */ | ||||||
| 	    {10,  0x07, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xc7, 0, 0, | 	    {10,  0x07, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xc7, 0, 0, | ||||||
| 	     0, 0, 0, 0} }, | 	     0, 0, 0, 0} }, | ||||||
| 	{0, 0x10, 0, F_D_IN, resp_write_filemarks, NULL,    /* WRITE FILEMARKS (6) */ | 	{0, 0x10, 0, DS_SSC, F_D_IN, resp_write_filemarks, NULL,   /* WRITE FILEMARKS (6) */ | ||||||
| 	    {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x11, 0, F_D_IN, resp_space, NULL,    /* SPACE (6) */ | 	{0, 0x11, 0, DS_SSC, F_D_IN, resp_space, NULL,    /* SPACE (6) */ | ||||||
| 	    {6,  0x07, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0x07, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| 	{0, 0x4, 0, 0, resp_format_medium, NULL,  /* FORMAT MEDIUM (6) */ | 	{0, 0x4, 0, DS_SSC, 0, resp_format_medium, NULL,  /* FORMAT MEDIUM (6) */ | ||||||
| 	    {6,  0x3, 0x7, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {6,  0x3, 0x7, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| /* 38 */ | 	{0, 0x19, 0, DS_SSC, F_D_IN, resp_erase, NULL,    /* ERASE (6) */ | ||||||
|  | 	    {6,  0x03, 0x33, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
|  | /* 39 */ | ||||||
| /* sentinel */ | /* sentinel */ | ||||||
| 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */ | 	{0xff, 0, 0, 0, 0, NULL, NULL,		/* terminating element */ | ||||||
| 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -1015,6 +1039,19 @@ static const int condition_met_result = SAM_STAT_CONDITION_MET; | ||||||
| static struct dentry *sdebug_debugfs_root; | static struct dentry *sdebug_debugfs_root; | ||||||
| static ASYNC_DOMAIN_EXCLUSIVE(sdebug_async_domain); | static ASYNC_DOMAIN_EXCLUSIVE(sdebug_async_domain); | ||||||
| 
 | 
 | ||||||
|  | static u32 sdebug_get_devsel(struct scsi_device *sdp) | ||||||
|  | { | ||||||
|  | 	unsigned char devtype = sdp->type; | ||||||
|  | 	u32 devsel; | ||||||
|  | 
 | ||||||
|  | 	if (devtype < 32) | ||||||
|  | 		devsel = (1 << devtype); | ||||||
|  | 	else | ||||||
|  | 		devsel = DS_ALL; | ||||||
|  | 
 | ||||||
|  | 	return devsel; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void sdebug_err_free(struct rcu_head *head) | static void sdebug_err_free(struct rcu_head *head) | ||||||
| { | { | ||||||
| 	struct sdebug_err_inject *inject = | 	struct sdebug_err_inject *inject = | ||||||
|  | @ -2032,13 +2069,19 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | ||||||
| 	unsigned char *cmd = scp->cmnd; | 	unsigned char *cmd = scp->cmnd; | ||||||
| 	u32 alloc_len, n; | 	u32 alloc_len, n; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	bool have_wlun, is_disk, is_zbc, is_disk_zbc; | 	bool have_wlun, is_disk, is_zbc, is_disk_zbc, is_tape; | ||||||
| 
 | 
 | ||||||
| 	alloc_len = get_unaligned_be16(cmd + 3); | 	alloc_len = get_unaligned_be16(cmd + 3); | ||||||
| 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); | 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); | ||||||
| 	if (! arr) | 	if (! arr) | ||||||
| 		return DID_REQUEUE << 16; | 		return DID_REQUEUE << 16; | ||||||
| 	is_disk = (sdebug_ptype == TYPE_DISK); | 	if (scp->device->type >= 32) { | ||||||
|  | 		is_disk = (sdebug_ptype == TYPE_DISK); | ||||||
|  | 		is_tape = (sdebug_ptype == TYPE_TAPE); | ||||||
|  | 	} else { | ||||||
|  | 		is_disk = (scp->device->type == TYPE_DISK); | ||||||
|  | 		is_tape = (scp->device->type == TYPE_TAPE); | ||||||
|  | 	} | ||||||
| 	is_zbc = devip->zoned; | 	is_zbc = devip->zoned; | ||||||
| 	is_disk_zbc = (is_disk || is_zbc); | 	is_disk_zbc = (is_disk || is_zbc); | ||||||
| 	have_wlun = scsi_is_wlun(scp->device->lun); | 	have_wlun = scsi_is_wlun(scp->device->lun); | ||||||
|  | @ -2047,7 +2090,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | ||||||
| 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) | 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) | ||||||
| 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */ | 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */ | ||||||
| 	else | 	else | ||||||
| 		pq_pdt = (sdebug_ptype & 0x1f); | 		pq_pdt = ((scp->device->type >= 32 ? | ||||||
|  | 				sdebug_ptype : scp->device->type) & 0x1f); | ||||||
| 	arr[0] = pq_pdt; | 	arr[0] = pq_pdt; | ||||||
| 	if (0x2 & cmd[1]) {  /* CMDDT bit set */ | 	if (0x2 & cmd[1]) {  /* CMDDT bit set */ | ||||||
| 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); | 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); | ||||||
|  | @ -2170,7 +2214,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | ||||||
| 	if (is_disk) {		/* SBC-4 no version claimed */ | 	if (is_disk) {		/* SBC-4 no version claimed */ | ||||||
| 		put_unaligned_be16(0x600, arr + n); | 		put_unaligned_be16(0x600, arr + n); | ||||||
| 		n += 2; | 		n += 2; | ||||||
| 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */ | 	} else if (is_tape) {	/* SSC-4 rev 3 */ | ||||||
| 		put_unaligned_be16(0x525, arr + n); | 		put_unaligned_be16(0x525, arr + n); | ||||||
| 		n += 2; | 		n += 2; | ||||||
| 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */ | 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */ | ||||||
|  | @ -2279,7 +2323,7 @@ static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | ||||||
| 	changing = (stopped_state != want_stop); | 	changing = (stopped_state != want_stop); | ||||||
| 	if (changing) | 	if (changing) | ||||||
| 		atomic_xchg(&devip->stopped, want_stop); | 		atomic_xchg(&devip->stopped, want_stop); | ||||||
| 	if (sdebug_ptype == TYPE_TAPE && !want_stop) { | 	if (scp->device->type == TYPE_TAPE && !want_stop) { | ||||||
| 		int i; | 		int i; | ||||||
| 
 | 
 | ||||||
| 		set_bit(SDEBUG_UA_NOT_READY_TO_READY, devip->uas_bm); /* not legal! */ | 		set_bit(SDEBUG_UA_NOT_READY_TO_READY, devip->uas_bm); /* not legal! */ | ||||||
|  | @ -2454,11 +2498,12 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, | ||||||
| 	u8 reporting_opts, req_opcode, sdeb_i, supp; | 	u8 reporting_opts, req_opcode, sdeb_i, supp; | ||||||
| 	u16 req_sa, u; | 	u16 req_sa, u; | ||||||
| 	u32 alloc_len, a_len; | 	u32 alloc_len, a_len; | ||||||
| 	int k, offset, len, errsts, count, bump, na; | 	int k, offset, len, errsts, bump, na; | ||||||
| 	const struct opcode_info_t *oip; | 	const struct opcode_info_t *oip; | ||||||
| 	const struct opcode_info_t *r_oip; | 	const struct opcode_info_t *r_oip; | ||||||
| 	u8 *arr; | 	u8 *arr; | ||||||
| 	u8 *cmd = scp->cmnd; | 	u8 *cmd = scp->cmnd; | ||||||
|  | 	u32 devsel = sdebug_get_devsel(scp->device); | ||||||
| 
 | 
 | ||||||
| 	rctd = !!(cmd[2] & 0x80); | 	rctd = !!(cmd[2] & 0x80); | ||||||
| 	reporting_opts = cmd[2] & 0x7; | 	reporting_opts = cmd[2] & 0x7; | ||||||
|  | @ -2481,34 +2526,30 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, | ||||||
| 	} | 	} | ||||||
| 	switch (reporting_opts) { | 	switch (reporting_opts) { | ||||||
| 	case 0:	/* all commands */ | 	case 0:	/* all commands */ | ||||||
| 		/* count number of commands */ |  | ||||||
| 		for (count = 0, oip = opcode_info_arr; |  | ||||||
| 		     oip->num_attached != 0xff; ++oip) { |  | ||||||
| 			if (F_INV_OP & oip->flags) |  | ||||||
| 				continue; |  | ||||||
| 			count += (oip->num_attached + 1); |  | ||||||
| 		} |  | ||||||
| 		bump = rctd ? 20 : 8; | 		bump = rctd ? 20 : 8; | ||||||
| 		put_unaligned_be32(count * bump, arr); |  | ||||||
| 		for (offset = 4, oip = opcode_info_arr; | 		for (offset = 4, oip = opcode_info_arr; | ||||||
| 		     oip->num_attached != 0xff && offset < a_len; ++oip) { | 		     oip->num_attached != 0xff && offset < a_len; ++oip) { | ||||||
| 			if (F_INV_OP & oip->flags) | 			if (F_INV_OP & oip->flags) | ||||||
| 				continue; | 				continue; | ||||||
|  | 			if ((devsel & oip->devsel) != 0) { | ||||||
|  | 				arr[offset] = oip->opcode; | ||||||
|  | 				put_unaligned_be16(oip->sa, arr + offset + 2); | ||||||
|  | 				if (rctd) | ||||||
|  | 					arr[offset + 5] |= 0x2; | ||||||
|  | 				if (FF_SA & oip->flags) | ||||||
|  | 					arr[offset + 5] |= 0x1; | ||||||
|  | 				put_unaligned_be16(oip->len_mask[0], arr + offset + 6); | ||||||
|  | 				if (rctd) | ||||||
|  | 					put_unaligned_be16(0xa, arr + offset + 8); | ||||||
|  | 				offset += bump; | ||||||
|  | 			} | ||||||
| 			na = oip->num_attached; | 			na = oip->num_attached; | ||||||
| 			arr[offset] = oip->opcode; |  | ||||||
| 			put_unaligned_be16(oip->sa, arr + offset + 2); |  | ||||||
| 			if (rctd) |  | ||||||
| 				arr[offset + 5] |= 0x2; |  | ||||||
| 			if (FF_SA & oip->flags) |  | ||||||
| 				arr[offset + 5] |= 0x1; |  | ||||||
| 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6); |  | ||||||
| 			if (rctd) |  | ||||||
| 				put_unaligned_be16(0xa, arr + offset + 8); |  | ||||||
| 			r_oip = oip; | 			r_oip = oip; | ||||||
| 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { | 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { | ||||||
| 				if (F_INV_OP & oip->flags) | 				if (F_INV_OP & oip->flags) | ||||||
| 					continue; | 					continue; | ||||||
| 				offset += bump; | 				if ((devsel & oip->devsel) == 0) | ||||||
|  | 					continue; | ||||||
| 				arr[offset] = oip->opcode; | 				arr[offset] = oip->opcode; | ||||||
| 				put_unaligned_be16(oip->sa, arr + offset + 2); | 				put_unaligned_be16(oip->sa, arr + offset + 2); | ||||||
| 				if (rctd) | 				if (rctd) | ||||||
|  | @ -2516,14 +2557,15 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, | ||||||
| 				if (FF_SA & oip->flags) | 				if (FF_SA & oip->flags) | ||||||
| 					arr[offset + 5] |= 0x1; | 					arr[offset + 5] |= 0x1; | ||||||
| 				put_unaligned_be16(oip->len_mask[0], | 				put_unaligned_be16(oip->len_mask[0], | ||||||
| 						   arr + offset + 6); | 						arr + offset + 6); | ||||||
| 				if (rctd) | 				if (rctd) | ||||||
| 					put_unaligned_be16(0xa, | 					put_unaligned_be16(0xa, | ||||||
| 							   arr + offset + 8); | 							   arr + offset + 8); | ||||||
|  | 				offset += bump; | ||||||
| 			} | 			} | ||||||
| 			oip = r_oip; | 			oip = r_oip; | ||||||
| 			offset += bump; |  | ||||||
| 		} | 		} | ||||||
|  | 		put_unaligned_be32(offset - 4, arr); | ||||||
| 		break; | 		break; | ||||||
| 	case 1:	/* one command: opcode only */ | 	case 1:	/* one command: opcode only */ | ||||||
| 	case 2:	/* one command: opcode plus service action */ | 	case 2:	/* one command: opcode plus service action */ | ||||||
|  | @ -2549,13 +2591,15 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, | ||||||
| 				return check_condition_result; | 				return check_condition_result; | ||||||
| 			} | 			} | ||||||
| 			if (0 == (FF_SA & oip->flags) && | 			if (0 == (FF_SA & oip->flags) && | ||||||
| 			    req_opcode == oip->opcode) | 				(devsel & oip->devsel) != 0 && | ||||||
|  | 				req_opcode == oip->opcode) | ||||||
| 				supp = 3; | 				supp = 3; | ||||||
| 			else if (0 == (FF_SA & oip->flags)) { | 			else if (0 == (FF_SA & oip->flags)) { | ||||||
| 				na = oip->num_attached; | 				na = oip->num_attached; | ||||||
| 				for (k = 0, oip = oip->arrp; k < na; | 				for (k = 0, oip = oip->arrp; k < na; | ||||||
| 				     ++k, ++oip) { | 				     ++k, ++oip) { | ||||||
| 					if (req_opcode == oip->opcode) | 					if (req_opcode == oip->opcode && | ||||||
|  | 						(devsel & oip->devsel) != 0) | ||||||
| 						break; | 						break; | ||||||
| 				} | 				} | ||||||
| 				supp = (k >= na) ? 1 : 3; | 				supp = (k >= na) ? 1 : 3; | ||||||
|  | @ -2563,7 +2607,8 @@ static int resp_rsup_opcodes(struct scsi_cmnd *scp, | ||||||
| 				na = oip->num_attached; | 				na = oip->num_attached; | ||||||
| 				for (k = 0, oip = oip->arrp; k < na; | 				for (k = 0, oip = oip->arrp; k < na; | ||||||
| 				     ++k, ++oip) { | 				     ++k, ++oip) { | ||||||
| 					if (req_sa == oip->sa) | 					if (req_sa == oip->sa && | ||||||
|  | 						(devsel & oip->devsel) != 0) | ||||||
| 						break; | 						break; | ||||||
| 				} | 				} | ||||||
| 				supp = (k >= na) ? 1 : 3; | 				supp = (k >= na) ? 1 : 3; | ||||||
|  | @ -2914,9 +2959,9 @@ static int resp_mode_sense(struct scsi_cmnd *scp, | ||||||
| 	subpcode = cmd[3]; | 	subpcode = cmd[3]; | ||||||
| 	msense_6 = (MODE_SENSE == cmd[0]); | 	msense_6 = (MODE_SENSE == cmd[0]); | ||||||
| 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10); | 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10); | ||||||
| 	is_disk = (sdebug_ptype == TYPE_DISK); | 	is_disk = (scp->device->type == TYPE_DISK); | ||||||
| 	is_zbc = devip->zoned; | 	is_zbc = devip->zoned; | ||||||
| 	is_tape = (sdebug_ptype == TYPE_TAPE); | 	is_tape = (scp->device->type == TYPE_TAPE); | ||||||
| 	if ((is_disk || is_zbc || is_tape) && !dbd) | 	if ((is_disk || is_zbc || is_tape) && !dbd) | ||||||
| 		bd_len = llbaa ? 16 : 8; | 		bd_len = llbaa ? 16 : 8; | ||||||
| 	else | 	else | ||||||
|  | @ -3131,7 +3176,7 @@ static int resp_mode_select(struct scsi_cmnd *scp, | ||||||
| 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); | 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); | ||||||
| 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); | 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); | ||||||
| 	off = (mselect6 ? 4 : 8); | 	off = (mselect6 ? 4 : 8); | ||||||
| 	if (sdebug_ptype == TYPE_TAPE) { | 	if (scp->device->type == TYPE_TAPE) { | ||||||
| 		int blksize; | 		int blksize; | ||||||
| 
 | 
 | ||||||
| 		if (bd_len != 8) { | 		if (bd_len != 8) { | ||||||
|  | @ -3196,7 +3241,7 @@ static int resp_mode_select(struct scsi_cmnd *scp, | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case 0xf:       /* Compression mode page */ | 	case 0xf:       /* Compression mode page */ | ||||||
| 		if (sdebug_ptype != TYPE_TAPE) | 		if (scp->device->type != TYPE_TAPE) | ||||||
| 			goto bad_pcode; | 			goto bad_pcode; | ||||||
| 		if ((arr[off + 2] & 0x40) != 0) { | 		if ((arr[off + 2] & 0x40) != 0) { | ||||||
| 			devip->tape_dce = (arr[off + 2] & 0x80) != 0; | 			devip->tape_dce = (arr[off + 2] & 0x80) != 0; | ||||||
|  | @ -3204,7 +3249,7 @@ static int resp_mode_select(struct scsi_cmnd *scp, | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case 0x11:	/* Medium Partition Mode Page (tape) */ | 	case 0x11:	/* Medium Partition Mode Page (tape) */ | ||||||
| 		if (sdebug_ptype == TYPE_TAPE) { | 		if (scp->device->type == TYPE_TAPE) { | ||||||
| 			int fld; | 			int fld; | ||||||
| 
 | 
 | ||||||
| 			fld = process_medium_part_m_pg(devip, &arr[off], pg_len); | 			fld = process_medium_part_m_pg(devip, &arr[off], pg_len); | ||||||
|  | @ -3563,6 +3608,30 @@ static int resp_space(struct scsi_cmnd *scp, | ||||||
| 	return check_condition_result; | 	return check_condition_result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | enum {SDEBUG_READ_POSITION_ARR_SZ = 20}; | ||||||
|  | static int resp_read_position(struct scsi_cmnd *scp, | ||||||
|  | 			struct sdebug_dev_info *devip) | ||||||
|  | { | ||||||
|  | 	u8 *cmd = scp->cmnd; | ||||||
|  | 	int all_length; | ||||||
|  | 	unsigned char arr[20]; | ||||||
|  | 	unsigned int pos; | ||||||
|  | 
 | ||||||
|  | 	all_length = get_unaligned_be16(cmd + 7); | ||||||
|  | 	if ((cmd[1] & 0xfe) != 0 || | ||||||
|  | 		all_length != 0) { /* only short form */ | ||||||
|  | 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, | ||||||
|  | 				all_length ? 7 : 1, 0); | ||||||
|  | 		return check_condition_result; | ||||||
|  | 	} | ||||||
|  | 	memset(arr, 0, SDEBUG_READ_POSITION_ARR_SZ); | ||||||
|  | 	arr[1] = devip->tape_partition; | ||||||
|  | 	pos = devip->tape_location[devip->tape_partition]; | ||||||
|  | 	put_unaligned_be32(pos, arr + 4); | ||||||
|  | 	put_unaligned_be32(pos, arr + 8); | ||||||
|  | 	return fill_from_dev_buffer(scp, arr, SDEBUG_READ_POSITION_ARR_SZ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int resp_rewind(struct scsi_cmnd *scp, | static int resp_rewind(struct scsi_cmnd *scp, | ||||||
| 		struct sdebug_dev_info *devip) | 		struct sdebug_dev_info *devip) | ||||||
| { | { | ||||||
|  | @ -3604,10 +3673,6 @@ static int resp_format_medium(struct scsi_cmnd *scp, | ||||||
| 	int res = 0; | 	int res = 0; | ||||||
| 	unsigned char *cmd = scp->cmnd; | 	unsigned char *cmd = scp->cmnd; | ||||||
| 
 | 
 | ||||||
| 	if (sdebug_ptype != TYPE_TAPE) { |  | ||||||
| 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 0, -1); |  | ||||||
| 		return check_condition_result; |  | ||||||
| 	} |  | ||||||
| 	if (cmd[2] > 2) { | 	if (cmd[2] > 2) { | ||||||
| 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 2, -1); | 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 2, -1); | ||||||
| 		return check_condition_result; | 		return check_condition_result; | ||||||
|  | @ -3631,6 +3696,19 @@ static int resp_format_medium(struct scsi_cmnd *scp, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int resp_erase(struct scsi_cmnd *scp, | ||||||
|  | 		struct sdebug_dev_info *devip) | ||||||
|  | { | ||||||
|  | 	int partition = devip->tape_partition; | ||||||
|  | 	int pos = devip->tape_location[partition]; | ||||||
|  | 	struct tape_block *blp; | ||||||
|  | 
 | ||||||
|  | 	blp = devip->tape_blocks[partition] + pos; | ||||||
|  | 	blp->fl_size = TAPE_BLOCK_EOD_FLAG; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) | static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) | ||||||
| { | { | ||||||
| 	return devip->nr_zones != 0; | 	return devip->nr_zones != 0; | ||||||
|  | @ -4467,9 +4545,6 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | ||||||
| 	u8 *cmd = scp->cmnd; | 	u8 *cmd = scp->cmnd; | ||||||
| 	bool meta_data_locked = false; | 	bool meta_data_locked = false; | ||||||
| 
 | 
 | ||||||
| 	if (sdebug_ptype == TYPE_TAPE) |  | ||||||
| 		return resp_read_tape(scp, devip); |  | ||||||
| 
 |  | ||||||
| 	switch (cmd[0]) { | 	switch (cmd[0]) { | ||||||
| 	case READ_16: | 	case READ_16: | ||||||
| 		ei_lba = 0; | 		ei_lba = 0; | ||||||
|  | @ -4839,9 +4914,6 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | ||||||
| 	u8 *cmd = scp->cmnd; | 	u8 *cmd = scp->cmnd; | ||||||
| 	bool meta_data_locked = false; | 	bool meta_data_locked = false; | ||||||
| 
 | 
 | ||||||
| 	if (sdebug_ptype == TYPE_TAPE) |  | ||||||
| 		return resp_write_tape(scp, devip); |  | ||||||
| 
 |  | ||||||
| 	switch (cmd[0]) { | 	switch (cmd[0]) { | ||||||
| 	case WRITE_16: | 	case WRITE_16: | ||||||
| 		ei_lba = 0; | 		ei_lba = 0; | ||||||
|  | @ -5573,7 +5645,6 @@ static int resp_sync_cache(struct scsi_cmnd *scp, | ||||||
|  * |  * | ||||||
|  * The pcode 0x34 is also used for READ POSITION by tape devices. |  * The pcode 0x34 is also used for READ POSITION by tape devices. | ||||||
|  */ |  */ | ||||||
| enum {SDEBUG_READ_POSITION_ARR_SZ = 20}; |  | ||||||
| static int resp_pre_fetch(struct scsi_cmnd *scp, | static int resp_pre_fetch(struct scsi_cmnd *scp, | ||||||
| 			  struct sdebug_dev_info *devip) | 			  struct sdebug_dev_info *devip) | ||||||
| { | { | ||||||
|  | @ -5585,31 +5656,6 @@ static int resp_pre_fetch(struct scsi_cmnd *scp, | ||||||
| 	struct sdeb_store_info *sip = devip2sip(devip, true); | 	struct sdeb_store_info *sip = devip2sip(devip, true); | ||||||
| 	u8 *fsp = sip->storep; | 	u8 *fsp = sip->storep; | ||||||
| 
 | 
 | ||||||
| 	if (sdebug_ptype == TYPE_TAPE) { |  | ||||||
| 		if (cmd[0] == PRE_FETCH) { /* READ POSITION (10) */ |  | ||||||
| 			int all_length; |  | ||||||
| 			unsigned char arr[20]; |  | ||||||
| 			unsigned int pos; |  | ||||||
| 
 |  | ||||||
| 			all_length = get_unaligned_be16(cmd + 7); |  | ||||||
| 			if ((cmd[1] & 0xfe) != 0 || |  | ||||||
| 				all_length != 0) { /* only short form */ |  | ||||||
| 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, |  | ||||||
| 						all_length ? 7 : 1, 0); |  | ||||||
| 				return check_condition_result; |  | ||||||
| 			} |  | ||||||
| 			memset(arr, 0, SDEBUG_READ_POSITION_ARR_SZ); |  | ||||||
| 			arr[1] = devip->tape_partition; |  | ||||||
| 			pos = devip->tape_location[devip->tape_partition]; |  | ||||||
| 			put_unaligned_be32(pos, arr + 4); |  | ||||||
| 			put_unaligned_be32(pos, arr + 8); |  | ||||||
| 			return fill_from_dev_buffer(scp, arr, |  | ||||||
| 						SDEBUG_READ_POSITION_ARR_SZ); |  | ||||||
| 		} |  | ||||||
| 		mk_sense_invalid_opcode(scp); |  | ||||||
| 		return check_condition_result; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */ | 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */ | ||||||
| 		lba = get_unaligned_be32(cmd + 2); | 		lba = get_unaligned_be32(cmd + 2); | ||||||
| 		nblks = get_unaligned_be16(cmd + 7); | 		nblks = get_unaligned_be16(cmd + 7); | ||||||
|  | @ -6645,7 +6691,7 @@ static void scsi_debug_sdev_destroy(struct scsi_device *sdp) | ||||||
| 
 | 
 | ||||||
| 	debugfs_remove(devip->debugfs_entry); | 	debugfs_remove(devip->debugfs_entry); | ||||||
| 
 | 
 | ||||||
| 	if (sdebug_ptype == TYPE_TAPE) { | 	if (sdp->type == TYPE_TAPE) { | ||||||
| 		kfree(devip->tape_blocks[0]); | 		kfree(devip->tape_blocks[0]); | ||||||
| 		devip->tape_blocks[0] = NULL; | 		devip->tape_blocks[0] = NULL; | ||||||
| 	} | 	} | ||||||
|  | @ -6833,18 +6879,16 @@ static int sdebug_fail_lun_reset(struct scsi_cmnd *cmnd) | ||||||
| 
 | 
 | ||||||
| static void scsi_tape_reset_clear(struct sdebug_dev_info *devip) | static void scsi_tape_reset_clear(struct sdebug_dev_info *devip) | ||||||
| { | { | ||||||
| 	if (sdebug_ptype == TYPE_TAPE) { | 	int i; | ||||||
| 		int i; |  | ||||||
| 
 | 
 | ||||||
| 		devip->tape_blksize = TAPE_DEF_BLKSIZE; | 	devip->tape_blksize = TAPE_DEF_BLKSIZE; | ||||||
| 		devip->tape_density = TAPE_DEF_DENSITY; | 	devip->tape_density = TAPE_DEF_DENSITY; | ||||||
| 		devip->tape_partition = 0; | 	devip->tape_partition = 0; | ||||||
| 		devip->tape_dce = 0; | 	devip->tape_dce = 0; | ||||||
| 		for (i = 0; i < TAPE_MAX_PARTITIONS; i++) | 	for (i = 0; i < TAPE_MAX_PARTITIONS; i++) | ||||||
| 			devip->tape_location[i] = 0; | 		devip->tape_location[i] = 0; | ||||||
| 		devip->tape_pending_nbr_partitions = -1; | 	devip->tape_pending_nbr_partitions = -1; | ||||||
| 		/* Don't reset partitioning? */ | 	/* Don't reset partitioning? */ | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) | static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) | ||||||
|  | @ -6862,7 +6906,8 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) | ||||||
| 	scsi_debug_stop_all_queued(sdp); | 	scsi_debug_stop_all_queued(sdp); | ||||||
| 	if (devip) { | 	if (devip) { | ||||||
| 		set_bit(SDEBUG_UA_POR, devip->uas_bm); | 		set_bit(SDEBUG_UA_POR, devip->uas_bm); | ||||||
| 		scsi_tape_reset_clear(devip); | 		if (SCpnt->device->type == TYPE_TAPE) | ||||||
|  | 			scsi_tape_reset_clear(devip); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (sdebug_fail_lun_reset(SCpnt)) { | 	if (sdebug_fail_lun_reset(SCpnt)) { | ||||||
|  | @ -6901,7 +6946,8 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) | ||||||
| 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { | 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { | ||||||
| 		if (devip->target == sdp->id) { | 		if (devip->target == sdp->id) { | ||||||
| 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); | 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); | ||||||
| 			scsi_tape_reset_clear(devip); | 			if (SCpnt->device->type == TYPE_TAPE) | ||||||
|  | 				scsi_tape_reset_clear(devip); | ||||||
| 			++k; | 			++k; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -6933,7 +6979,8 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { | 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { | ||||||
| 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); | 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); | ||||||
| 		scsi_tape_reset_clear(devip); | 		if (SCpnt->device->type == TYPE_TAPE) | ||||||
|  | 			scsi_tape_reset_clear(devip); | ||||||
| 		++k; | 		++k; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -6957,7 +7004,8 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) | ||||||
| 		list_for_each_entry(devip, &sdbg_host->dev_info_list, | 		list_for_each_entry(devip, &sdbg_host->dev_info_list, | ||||||
| 				    dev_list) { | 				    dev_list) { | ||||||
| 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); | 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); | ||||||
| 			scsi_tape_reset_clear(devip); | 			if (SCpnt->device->type == TYPE_TAPE) | ||||||
|  | 				scsi_tape_reset_clear(devip); | ||||||
| 			++k; | 			++k; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -9173,6 +9221,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, | ||||||
| 	u32 flags; | 	u32 flags; | ||||||
| 	u16 sa; | 	u16 sa; | ||||||
| 	u8 opcode = cmd[0]; | 	u8 opcode = cmd[0]; | ||||||
|  | 	u32 devsel = sdebug_get_devsel(scp->device); | ||||||
| 	bool has_wlun_rl; | 	bool has_wlun_rl; | ||||||
| 	bool inject_now; | 	bool inject_now; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
|  | @ -9252,12 +9301,14 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, | ||||||
| 			else | 			else | ||||||
| 				sa = get_unaligned_be16(cmd + 8); | 				sa = get_unaligned_be16(cmd + 8); | ||||||
| 			for (k = 0; k <= na; oip = r_oip->arrp + k++) { | 			for (k = 0; k <= na; oip = r_oip->arrp + k++) { | ||||||
| 				if (opcode == oip->opcode && sa == oip->sa) | 				if (opcode == oip->opcode && sa == oip->sa && | ||||||
|  | 					(devsel & oip->devsel) != 0) | ||||||
| 					break; | 					break; | ||||||
| 			} | 			} | ||||||
| 		} else {   /* since no service action only check opcode */ | 		} else {   /* since no service action only check opcode */ | ||||||
| 			for (k = 0; k <= na; oip = r_oip->arrp + k++) { | 			for (k = 0; k <= na; oip = r_oip->arrp + k++) { | ||||||
| 				if (opcode == oip->opcode) | 				if (opcode == oip->opcode && | ||||||
|  | 					(devsel & oip->devsel) != 0) | ||||||
| 					break; | 					break; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -485,33 +485,6 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, | ||||||
| 	return ERR_PTR(-ENOENT); | 	return ERR_PTR(-ENOENT); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * scsi_dev_info_list_del_keyed - remove one dev_info list entry. |  | ||||||
|  * @vendor:	vendor string |  | ||||||
|  * @model:	model (product) string |  | ||||||
|  * @key:	specify list to use |  | ||||||
|  * |  | ||||||
|  * Description: |  | ||||||
|  *	Remove and destroy one dev_info entry for @vendor, @model |  | ||||||
|  *	in list specified by @key. |  | ||||||
|  * |  | ||||||
|  * Returns: 0 OK, -error on failure. |  | ||||||
|  **/ |  | ||||||
| int scsi_dev_info_list_del_keyed(char *vendor, char *model, |  | ||||||
| 				 enum scsi_devinfo_key key) |  | ||||||
| { |  | ||||||
| 	struct scsi_dev_info_list *found; |  | ||||||
| 
 |  | ||||||
| 	found = scsi_dev_info_list_find(vendor, model, key); |  | ||||||
| 	if (IS_ERR(found)) |  | ||||||
| 		return PTR_ERR(found); |  | ||||||
| 
 |  | ||||||
| 	list_del(&found->dev_info_list); |  | ||||||
| 	kfree(found); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(scsi_dev_info_list_del_keyed); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. |  * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. | ||||||
|  * @dev_list:	string of device flags to add |  * @dev_list:	string of device flags to add | ||||||
|  |  | ||||||
|  | @ -79,8 +79,6 @@ extern int scsi_dev_info_list_add_keyed(int compatible, char *vendor, | ||||||
| 					char *model, char *strflags, | 					char *model, char *strflags, | ||||||
| 					blist_flags_t flags, | 					blist_flags_t flags, | ||||||
| 					enum scsi_devinfo_key key); | 					enum scsi_devinfo_key key); | ||||||
| extern int scsi_dev_info_list_del_keyed(char *vendor, char *model, |  | ||||||
| 					enum scsi_devinfo_key key); |  | ||||||
| extern int scsi_dev_info_add_list(enum scsi_devinfo_key key, const char *name); | extern int scsi_dev_info_add_list(enum scsi_devinfo_key key, const char *name); | ||||||
| extern int scsi_dev_info_remove_list(enum scsi_devinfo_key key); | extern int scsi_dev_info_remove_list(enum scsi_devinfo_key key); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3509,7 +3509,7 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles) | ||||||
| 		 *  state as the LLDD would not have had an rport | 		 *  state as the LLDD would not have had an rport | ||||||
| 		 *  reference to pass us. | 		 *  reference to pass us. | ||||||
| 		 * | 		 * | ||||||
| 		 * Take no action on the del_timer failure as the state | 		 * Take no action on the timer_delete() failure as the state | ||||||
| 		 * machine state change will validate the | 		 * machine state change will validate the | ||||||
| 		 * transaction. | 		 * transaction. | ||||||
| 		 */ | 		 */ | ||||||
|  |  | ||||||
|  | @ -3215,7 +3215,7 @@ static bool sd_is_perm_stream(struct scsi_disk *sdkp, unsigned int stream_id) | ||||||
| 		return false; | 		return false; | ||||||
| 	if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status)) | 	if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status)) | ||||||
| 		return false; | 		return false; | ||||||
| 	return buf.h.stream_status[0].perm; | 	return buf.s.perm; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer) | static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer) | ||||||
|  |  | ||||||
|  | @ -1658,8 +1658,7 @@ static void register_sg_sysctls(void) | ||||||
| 
 | 
 | ||||||
| static void unregister_sg_sysctls(void) | static void unregister_sg_sysctls(void) | ||||||
| { | { | ||||||
| 	if (hdr) | 	unregister_sysctl_table(hdr); | ||||||
| 		unregister_sysctl_table(hdr); |  | ||||||
| } | } | ||||||
| #else | #else | ||||||
| #define register_sg_sysctls() do { } while (0) | #define register_sg_sysctls() do { } while (0) | ||||||
|  |  | ||||||
|  | @ -33,11 +33,11 @@ | ||||||
| #define BUILD_TIMESTAMP | #define BUILD_TIMESTAMP | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #define DRIVER_VERSION		"2.1.30-031" | #define DRIVER_VERSION		"2.1.34-035" | ||||||
| #define DRIVER_MAJOR		2 | #define DRIVER_MAJOR		2 | ||||||
| #define DRIVER_MINOR		1 | #define DRIVER_MINOR		1 | ||||||
| #define DRIVER_RELEASE		30 | #define DRIVER_RELEASE		34 | ||||||
| #define DRIVER_REVISION		31 | #define DRIVER_REVISION		35 | ||||||
| 
 | 
 | ||||||
| #define DRIVER_NAME		"Microchip SmartPQI Driver (v" \ | #define DRIVER_NAME		"Microchip SmartPQI Driver (v" \ | ||||||
| 				DRIVER_VERSION BUILD_TIMESTAMP ")" | 				DRIVER_VERSION BUILD_TIMESTAMP ")" | ||||||
|  | @ -68,6 +68,7 @@ static struct pqi_cmd_priv *pqi_cmd_priv(struct scsi_cmnd *cmd) | ||||||
| static void pqi_verify_structures(void); | static void pqi_verify_structures(void); | ||||||
| static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info, | static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info, | ||||||
| 	enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason); | 	enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason); | ||||||
|  | static void pqi_take_ctrl_devices_offline(struct pqi_ctrl_info *ctrl_info); | ||||||
| static void pqi_ctrl_offline_worker(struct work_struct *work); | static void pqi_ctrl_offline_worker(struct work_struct *work); | ||||||
| static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info); | static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info); | ||||||
| static void pqi_scan_start(struct Scsi_Host *shost); | static void pqi_scan_start(struct Scsi_Host *shost); | ||||||
|  | @ -2011,18 +2012,31 @@ static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info, | ||||||
| 			PQI_DEV_INFO_BUFFER_LENGTH - count, | 			PQI_DEV_INFO_BUFFER_LENGTH - count, | ||||||
| 			"-:-"); | 			"-:-"); | ||||||
| 
 | 
 | ||||||
| 	if (pqi_is_logical_device(device)) | 	if (pqi_is_logical_device(device)) { | ||||||
| 		count += scnprintf(buffer + count, | 		count += scnprintf(buffer + count, | ||||||
| 			PQI_DEV_INFO_BUFFER_LENGTH - count, | 			PQI_DEV_INFO_BUFFER_LENGTH - count, | ||||||
| 			" %08x%08x", | 			" %08x%08x", | ||||||
| 			*((u32 *)&device->scsi3addr), | 			*((u32 *)&device->scsi3addr), | ||||||
| 			*((u32 *)&device->scsi3addr[4])); | 			*((u32 *)&device->scsi3addr[4])); | ||||||
| 	else | 	} else if (ctrl_info->rpl_extended_format_4_5_supported) { | ||||||
|  | 		if (device->device_type == SA_DEVICE_TYPE_NVME) | ||||||
|  | 			count += scnprintf(buffer + count, | ||||||
|  | 					PQI_DEV_INFO_BUFFER_LENGTH - count, | ||||||
|  | 					" %016llx%016llx", | ||||||
|  | 					get_unaligned_be64(&device->wwid[0]), | ||||||
|  | 					get_unaligned_be64(&device->wwid[8])); | ||||||
|  | 		else | ||||||
|  | 			count += scnprintf(buffer + count, | ||||||
|  | 					PQI_DEV_INFO_BUFFER_LENGTH - count, | ||||||
|  | 					" %016llx", | ||||||
|  | 					get_unaligned_be64(&device->wwid[0])); | ||||||
|  | 	} else { | ||||||
| 		count += scnprintf(buffer + count, | 		count += scnprintf(buffer + count, | ||||||
| 			PQI_DEV_INFO_BUFFER_LENGTH - count, | 			PQI_DEV_INFO_BUFFER_LENGTH - count, | ||||||
| 			" %016llx%016llx", | 			" %016llx", | ||||||
| 			get_unaligned_be64(&device->wwid[0]), | 			get_unaligned_be64(&device->wwid[0])); | ||||||
| 			get_unaligned_be64(&device->wwid[8])); | 	} | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, | 	count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, | ||||||
| 		" %s %.8s %.16s ", | 		" %s %.8s %.16s ", | ||||||
|  | @ -5990,7 +6004,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info, | ||||||
| 			pqi_stream_data->next_lba = rmd.first_block + | 			pqi_stream_data->next_lba = rmd.first_block + | ||||||
| 				rmd.block_cnt; | 				rmd.block_cnt; | ||||||
| 			pqi_stream_data->last_accessed = jiffies; | 			pqi_stream_data->last_accessed = jiffies; | ||||||
| 			per_cpu_ptr(device->raid_io_stats, smp_processor_id())->write_stream_cnt++; | 			per_cpu_ptr(device->raid_io_stats, raw_smp_processor_id())->write_stream_cnt++; | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -6069,7 +6083,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm | ||||||
| 			rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group); | 			rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group); | ||||||
| 			if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) { | 			if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) { | ||||||
| 				raid_bypassed = true; | 				raid_bypassed = true; | ||||||
| 				per_cpu_ptr(device->raid_io_stats, smp_processor_id())->raid_bypass_cnt++; | 				per_cpu_ptr(device->raid_io_stats, raw_smp_processor_id())->raid_bypass_cnt++; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if (!raid_bypassed) | 		if (!raid_bypassed) | ||||||
|  | @ -9129,6 +9143,7 @@ static void pqi_take_ctrl_offline_deferred(struct pqi_ctrl_info *ctrl_info) | ||||||
| 	pqi_ctrl_wait_until_quiesced(ctrl_info); | 	pqi_ctrl_wait_until_quiesced(ctrl_info); | ||||||
| 	pqi_fail_all_outstanding_requests(ctrl_info); | 	pqi_fail_all_outstanding_requests(ctrl_info); | ||||||
| 	pqi_ctrl_unblock_requests(ctrl_info); | 	pqi_ctrl_unblock_requests(ctrl_info); | ||||||
|  | 	pqi_take_ctrl_devices_offline(ctrl_info); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void pqi_ctrl_offline_worker(struct work_struct *work) | static void pqi_ctrl_offline_worker(struct work_struct *work) | ||||||
|  | @ -9203,6 +9218,27 @@ static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info, | ||||||
| 	schedule_work(&ctrl_info->ctrl_offline_work); | 	schedule_work(&ctrl_info->ctrl_offline_work); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void pqi_take_ctrl_devices_offline(struct pqi_ctrl_info *ctrl_info) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	struct pqi_scsi_dev *device; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); | ||||||
|  | 	list_for_each_entry(device, &ctrl_info->scsi_device_list, scsi_device_list_entry) { | ||||||
|  | 		rc = list_is_last(&device->scsi_device_list_entry, &ctrl_info->scsi_device_list); | ||||||
|  | 		if (rc) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * Is the sdev pointer NULL? | ||||||
|  | 		 */ | ||||||
|  | 		if (device->sdev) | ||||||
|  | 			scsi_device_set_state(device->sdev, SDEV_OFFLINE); | ||||||
|  | 	} | ||||||
|  | 	spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void pqi_print_ctrl_info(struct pci_dev *pci_dev, | static void pqi_print_ctrl_info(struct pci_dev *pci_dev, | ||||||
| 	const struct pci_device_id *id) | 	const struct pci_device_id *id) | ||||||
| { | { | ||||||
|  | @ -9709,6 +9745,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       0x1bd4, 0x0089) | 			       0x1bd4, 0x0089) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 				0x1bd4, 0x00a3) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       0x1ff9, 0x00a1) | 			       0x1ff9, 0x00a1) | ||||||
|  | @ -10045,6 +10085,30 @@ static const struct pci_device_id pqi_pci_id_table[] = { | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       PCI_VENDOR_ID_ADAPTEC2, 0x14f0) | 			       PCI_VENDOR_ID_ADAPTEC2, 0x14f0) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x207d, 0x4044) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x207d, 0x4054) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x207d, 0x4084) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x207d, 0x4094) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x207d, 0x4140) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x207d, 0x4240) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       PCI_VENDOR_ID_ADVANTECH, 0x8312) | 			       PCI_VENDOR_ID_ADVANTECH, 0x8312) | ||||||
|  | @ -10261,6 +10325,14 @@ static const struct pci_device_id pqi_pci_id_table[] = { | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       0x1cc4, 0x0201) | 			       0x1cc4, 0x0201) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x1018, 0x8238) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       0x1f3f, 0x0610) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       PCI_VENDOR_ID_LENOVO, 0x0220) | 			       PCI_VENDOR_ID_LENOVO, 0x0220) | ||||||
|  | @ -10269,10 +10341,30 @@ static const struct pci_device_id pqi_pci_id_table[] = { | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       PCI_VENDOR_ID_LENOVO, 0x0221) | 			       PCI_VENDOR_ID_LENOVO, 0x0221) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0222) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0223) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0224) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0225) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       PCI_VENDOR_ID_LENOVO, 0x0520) | 			       PCI_VENDOR_ID_LENOVO, 0x0520) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0521) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       PCI_VENDOR_ID_LENOVO, 0x0522) | 			       PCI_VENDOR_ID_LENOVO, 0x0522) | ||||||
|  | @ -10293,6 +10385,26 @@ static const struct pci_device_id pqi_pci_id_table[] = { | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       PCI_VENDOR_ID_LENOVO, 0x0623) | 			       PCI_VENDOR_ID_LENOVO, 0x0623) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0624) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0625) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0626) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0627) | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 			       PCI_VENDOR_ID_LENOVO, 0x0628) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 				0x1014, 0x0718) | 				0x1014, 0x0718) | ||||||
|  | @ -10321,6 +10433,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       0x1137, 0x0300) | 			       0x1137, 0x0300) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 				0x1ded, 0x3301) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       0x1ff9, 0x0045) | 			       0x1ff9, 0x0045) | ||||||
|  | @ -10469,6 +10585,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 				0x1f51, 0x100a) | 				0x1f51, 0x100a) | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
|  | 				0x1f51, 0x100b) | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, | ||||||
| 			       0x1f51, 0x100e) | 			       0x1f51, 0x100e) | ||||||
|  |  | ||||||
|  | @ -21,20 +21,63 @@ | ||||||
| 
 | 
 | ||||||
| #include <soc/qcom/ice.h> | #include <soc/qcom/ice.h> | ||||||
| 
 | 
 | ||||||
| #define AES_256_XTS_KEY_SIZE			64 | #define AES_256_XTS_KEY_SIZE			64   /* for raw keys only */ | ||||||
|  | #define QCOM_ICE_HWKM_WRAPPED_KEY_SIZE		100  /* assuming HWKM v2 */ | ||||||
| 
 | 
 | ||||||
| /* QCOM ICE registers */ | /* QCOM ICE registers */ | ||||||
| #define QCOM_ICE_REG_VERSION			0x0008 |  | ||||||
| #define QCOM_ICE_REG_FUSE_SETTING		0x0010 |  | ||||||
| #define QCOM_ICE_REG_BIST_STATUS		0x0070 |  | ||||||
| #define QCOM_ICE_REG_ADVANCED_CONTROL		0x1000 |  | ||||||
| 
 | 
 | ||||||
| /* BIST ("built-in self-test") status flags */ | #define QCOM_ICE_REG_CONTROL			0x0000 | ||||||
|  | #define QCOM_ICE_LEGACY_MODE_ENABLED		BIT(0) | ||||||
|  | 
 | ||||||
|  | #define QCOM_ICE_REG_VERSION			0x0008 | ||||||
|  | 
 | ||||||
|  | #define QCOM_ICE_REG_FUSE_SETTING		0x0010 | ||||||
|  | #define QCOM_ICE_FUSE_SETTING_MASK		BIT(0) | ||||||
|  | #define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK	BIT(1) | ||||||
|  | #define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK	BIT(2) | ||||||
|  | 
 | ||||||
|  | #define QCOM_ICE_REG_BIST_STATUS		0x0070 | ||||||
| #define QCOM_ICE_BIST_STATUS_MASK		GENMASK(31, 28) | #define QCOM_ICE_BIST_STATUS_MASK		GENMASK(31, 28) | ||||||
| 
 | 
 | ||||||
| #define QCOM_ICE_FUSE_SETTING_MASK		0x1 | #define QCOM_ICE_REG_ADVANCED_CONTROL		0x1000 | ||||||
| #define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK	0x2 | 
 | ||||||
| #define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK	0x4 | #define QCOM_ICE_REG_CRYPTOCFG_BASE		0x4040 | ||||||
|  | #define QCOM_ICE_REG_CRYPTOCFG_SIZE		0x80 | ||||||
|  | #define QCOM_ICE_REG_CRYPTOCFG(slot) (QCOM_ICE_REG_CRYPTOCFG_BASE + \ | ||||||
|  | 				      QCOM_ICE_REG_CRYPTOCFG_SIZE * (slot)) | ||||||
|  | union crypto_cfg { | ||||||
|  | 	__le32 regval; | ||||||
|  | 	struct { | ||||||
|  | 		u8 dusize; | ||||||
|  | 		u8 capidx; | ||||||
|  | 		u8 reserved; | ||||||
|  | #define QCOM_ICE_HWKM_CFG_ENABLE_VAL		BIT(7) | ||||||
|  | 		u8 cfge; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* QCOM ICE HWKM (Hardware Key Manager) registers */ | ||||||
|  | 
 | ||||||
|  | #define HWKM_OFFSET				0x8000 | ||||||
|  | 
 | ||||||
|  | #define QCOM_ICE_REG_HWKM_TZ_KM_CTL		(HWKM_OFFSET + 0x1000) | ||||||
|  | #define QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL	(BIT(1) | BIT(2)) | ||||||
|  | 
 | ||||||
|  | #define QCOM_ICE_REG_HWKM_TZ_KM_STATUS		(HWKM_OFFSET + 0x1004) | ||||||
|  | #define QCOM_ICE_HWKM_KT_CLEAR_DONE		BIT(0) | ||||||
|  | #define QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE	BIT(1) | ||||||
|  | #define QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE	BIT(2) | ||||||
|  | #define QCOM_ICE_HWKM_CRYPTO_BIST_DONE_V2	BIT(7) | ||||||
|  | #define QCOM_ICE_HWKM_BIST_DONE_V2		BIT(9) | ||||||
|  | 
 | ||||||
|  | #define QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS (HWKM_OFFSET + 0x2008) | ||||||
|  | #define QCOM_ICE_HWKM_RSP_FIFO_CLEAR_VAL	BIT(3) | ||||||
|  | 
 | ||||||
|  | #define QCOM_ICE_REG_HWKM_BANK0_BBAC_0		(HWKM_OFFSET + 0x5000) | ||||||
|  | #define QCOM_ICE_REG_HWKM_BANK0_BBAC_1		(HWKM_OFFSET + 0x5004) | ||||||
|  | #define QCOM_ICE_REG_HWKM_BANK0_BBAC_2		(HWKM_OFFSET + 0x5008) | ||||||
|  | #define QCOM_ICE_REG_HWKM_BANK0_BBAC_3		(HWKM_OFFSET + 0x500C) | ||||||
|  | #define QCOM_ICE_REG_HWKM_BANK0_BBAC_4		(HWKM_OFFSET + 0x5010) | ||||||
| 
 | 
 | ||||||
| #define qcom_ice_writel(engine, val, reg)	\ | #define qcom_ice_writel(engine, val, reg)	\ | ||||||
| 	writel((val), (engine)->base + (reg)) | 	writel((val), (engine)->base + (reg)) | ||||||
|  | @ -42,11 +85,18 @@ | ||||||
| #define qcom_ice_readl(engine, reg)	\ | #define qcom_ice_readl(engine, reg)	\ | ||||||
| 	readl((engine)->base + (reg)) | 	readl((engine)->base + (reg)) | ||||||
| 
 | 
 | ||||||
|  | static bool qcom_ice_use_wrapped_keys; | ||||||
|  | module_param_named(use_wrapped_keys, qcom_ice_use_wrapped_keys, bool, 0660); | ||||||
|  | MODULE_PARM_DESC(use_wrapped_keys, | ||||||
|  | 		 "Support wrapped keys instead of raw keys, if available on the platform"); | ||||||
|  | 
 | ||||||
| struct qcom_ice { | struct qcom_ice { | ||||||
| 	struct device *dev; | 	struct device *dev; | ||||||
| 	void __iomem *base; | 	void __iomem *base; | ||||||
| 
 | 
 | ||||||
| 	struct clk *core_clk; | 	struct clk *core_clk; | ||||||
|  | 	bool use_hwkm; | ||||||
|  | 	bool hwkm_init_complete; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool qcom_ice_check_supported(struct qcom_ice *ice) | static bool qcom_ice_check_supported(struct qcom_ice *ice) | ||||||
|  | @ -76,6 +126,35 @@ static bool qcom_ice_check_supported(struct qcom_ice *ice) | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Check for HWKM support and decide whether to use it or not.  ICE | ||||||
|  | 	 * v3.2.1 and later have HWKM v2.  ICE v3.2.0 has HWKM v1.  Earlier ICE | ||||||
|  | 	 * versions don't have HWKM at all.  However, for HWKM to be fully | ||||||
|  | 	 * usable by Linux, the TrustZone software also needs to support certain | ||||||
|  | 	 * SCM calls including the ones to generate and prepare keys.  That | ||||||
|  | 	 * effectively makes the earliest supported SoC be SM8650, which has | ||||||
|  | 	 * HWKM v2.  Therefore, this driver doesn't include support for HWKM v1, | ||||||
|  | 	 * and it checks for the SCM call support before it decides to use HWKM. | ||||||
|  | 	 * | ||||||
|  | 	 * Also, since HWKM and legacy mode are mutually exclusive, and | ||||||
|  | 	 * ICE-capable storage driver(s) need to know early on whether to | ||||||
|  | 	 * advertise support for raw keys or wrapped keys, HWKM cannot be used | ||||||
|  | 	 * unconditionally.  A module parameter is used to opt into using it. | ||||||
|  | 	 */ | ||||||
|  | 	if ((major >= 4 || | ||||||
|  | 	     (major == 3 && (minor >= 3 || (minor == 2 && step >= 1)))) && | ||||||
|  | 	    qcom_scm_has_wrapped_key_support()) { | ||||||
|  | 		if (qcom_ice_use_wrapped_keys) { | ||||||
|  | 			dev_info(dev, "Using HWKM. Supporting wrapped keys only.\n"); | ||||||
|  | 			ice->use_hwkm = true; | ||||||
|  | 		} else { | ||||||
|  | 			dev_info(dev, "Not using HWKM. Supporting raw keys only.\n"); | ||||||
|  | 		} | ||||||
|  | 	} else if (qcom_ice_use_wrapped_keys) { | ||||||
|  | 		dev_warn(dev, "A supported HWKM is not present. Ignoring qcom_ice.use_wrapped_keys=1.\n"); | ||||||
|  | 	} else { | ||||||
|  | 		dev_info(dev, "A supported HWKM is not present. Supporting raw keys only.\n"); | ||||||
|  | 	} | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -123,17 +202,71 @@ static int qcom_ice_wait_bist_status(struct qcom_ice *ice) | ||||||
| 	err = readl_poll_timeout(ice->base + QCOM_ICE_REG_BIST_STATUS, | 	err = readl_poll_timeout(ice->base + QCOM_ICE_REG_BIST_STATUS, | ||||||
| 				 regval, !(regval & QCOM_ICE_BIST_STATUS_MASK), | 				 regval, !(regval & QCOM_ICE_BIST_STATUS_MASK), | ||||||
| 				 50, 5000); | 				 50, 5000); | ||||||
| 	if (err) | 	if (err) { | ||||||
| 		dev_err(ice->dev, "Timed out waiting for ICE self-test to complete\n"); | 		dev_err(ice->dev, "Timed out waiting for ICE self-test to complete\n"); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return err; | 	if (ice->use_hwkm && | ||||||
|  | 	    qcom_ice_readl(ice, QCOM_ICE_REG_HWKM_TZ_KM_STATUS) != | ||||||
|  | 	    (QCOM_ICE_HWKM_KT_CLEAR_DONE | | ||||||
|  | 	     QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE | | ||||||
|  | 	     QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE | | ||||||
|  | 	     QCOM_ICE_HWKM_CRYPTO_BIST_DONE_V2 | | ||||||
|  | 	     QCOM_ICE_HWKM_BIST_DONE_V2)) { | ||||||
|  | 		dev_err(ice->dev, "HWKM self-test error!\n"); | ||||||
|  | 		/*
 | ||||||
|  | 		 * Too late to revoke use_hwkm here, as it was already | ||||||
|  | 		 * propagated up the stack into the crypto capabilities. | ||||||
|  | 		 */ | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void qcom_ice_hwkm_init(struct qcom_ice *ice) | ||||||
|  | { | ||||||
|  | 	u32 regval; | ||||||
|  | 
 | ||||||
|  | 	if (!ice->use_hwkm) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	BUILD_BUG_ON(QCOM_ICE_HWKM_WRAPPED_KEY_SIZE > | ||||||
|  | 		     BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE); | ||||||
|  | 	/*
 | ||||||
|  | 	 * When ICE is in HWKM mode, it only supports wrapped keys. | ||||||
|  | 	 * When ICE is in legacy mode, it only supports raw keys. | ||||||
|  | 	 * | ||||||
|  | 	 * Put ICE in HWKM mode.  ICE defaults to legacy mode. | ||||||
|  | 	 */ | ||||||
|  | 	regval = qcom_ice_readl(ice, QCOM_ICE_REG_CONTROL); | ||||||
|  | 	regval &= ~QCOM_ICE_LEGACY_MODE_ENABLED; | ||||||
|  | 	qcom_ice_writel(ice, regval, QCOM_ICE_REG_CONTROL); | ||||||
|  | 
 | ||||||
|  | 	/* Disable CRC checks.  This HWKM feature is not used. */ | ||||||
|  | 	qcom_ice_writel(ice, QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL, | ||||||
|  | 			QCOM_ICE_REG_HWKM_TZ_KM_CTL); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Allow the HWKM slave to read and write the keyslots in the ICE HWKM | ||||||
|  | 	 * slave.  Without this, TrustZone cannot program keys into ICE. | ||||||
|  | 	 */ | ||||||
|  | 	qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_0); | ||||||
|  | 	qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_1); | ||||||
|  | 	qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_2); | ||||||
|  | 	qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_3); | ||||||
|  | 	qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_4); | ||||||
|  | 
 | ||||||
|  | 	/* Clear the HWKM response FIFO. */ | ||||||
|  | 	qcom_ice_writel(ice, QCOM_ICE_HWKM_RSP_FIFO_CLEAR_VAL, | ||||||
|  | 			QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS); | ||||||
|  | 	ice->hwkm_init_complete = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int qcom_ice_enable(struct qcom_ice *ice) | int qcom_ice_enable(struct qcom_ice *ice) | ||||||
| { | { | ||||||
| 	qcom_ice_low_power_mode_enable(ice); | 	qcom_ice_low_power_mode_enable(ice); | ||||||
| 	qcom_ice_optimization_enable(ice); | 	qcom_ice_optimization_enable(ice); | ||||||
| 
 | 	qcom_ice_hwkm_init(ice); | ||||||
| 	return qcom_ice_wait_bist_status(ice); | 	return qcom_ice_wait_bist_status(ice); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(qcom_ice_enable); | EXPORT_SYMBOL_GPL(qcom_ice_enable); | ||||||
|  | @ -149,7 +282,7 @@ int qcom_ice_resume(struct qcom_ice *ice) | ||||||
| 			err); | 			err); | ||||||
| 		return err; | 		return err; | ||||||
| 	} | 	} | ||||||
| 
 | 	qcom_ice_hwkm_init(ice); | ||||||
| 	return qcom_ice_wait_bist_status(ice); | 	return qcom_ice_wait_bist_status(ice); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(qcom_ice_resume); | EXPORT_SYMBOL_GPL(qcom_ice_resume); | ||||||
|  | @ -157,15 +290,58 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume); | ||||||
| int qcom_ice_suspend(struct qcom_ice *ice) | int qcom_ice_suspend(struct qcom_ice *ice) | ||||||
| { | { | ||||||
| 	clk_disable_unprepare(ice->core_clk); | 	clk_disable_unprepare(ice->core_clk); | ||||||
|  | 	ice->hwkm_init_complete = false; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(qcom_ice_suspend); | EXPORT_SYMBOL_GPL(qcom_ice_suspend); | ||||||
| 
 | 
 | ||||||
| int qcom_ice_program_key(struct qcom_ice *ice, | static unsigned int translate_hwkm_slot(struct qcom_ice *ice, unsigned int slot) | ||||||
| 			 u8 algorithm_id, u8 key_size, | { | ||||||
| 			 const u8 crypto_key[], u8 data_unit_size, | 	return slot * 2; | ||||||
| 			 int slot) | } | ||||||
|  | 
 | ||||||
|  | static int qcom_ice_program_wrapped_key(struct qcom_ice *ice, unsigned int slot, | ||||||
|  | 					const struct blk_crypto_key *bkey) | ||||||
|  | { | ||||||
|  | 	struct device *dev = ice->dev; | ||||||
|  | 	union crypto_cfg cfg = { | ||||||
|  | 		.dusize = bkey->crypto_cfg.data_unit_size / 512, | ||||||
|  | 		.capidx = QCOM_SCM_ICE_CIPHER_AES_256_XTS, | ||||||
|  | 		.cfge = QCOM_ICE_HWKM_CFG_ENABLE_VAL, | ||||||
|  | 	}; | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	if (!ice->use_hwkm) { | ||||||
|  | 		dev_err_ratelimited(dev, "Got wrapped key when not using HWKM\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	if (!ice->hwkm_init_complete) { | ||||||
|  | 		dev_err_ratelimited(dev, "HWKM not yet initialized\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Clear CFGE before programming the key. */ | ||||||
|  | 	qcom_ice_writel(ice, 0x0, QCOM_ICE_REG_CRYPTOCFG(slot)); | ||||||
|  | 
 | ||||||
|  | 	/* Call into TrustZone to program the wrapped key using HWKM. */ | ||||||
|  | 	err = qcom_scm_ice_set_key(translate_hwkm_slot(ice, slot), bkey->bytes, | ||||||
|  | 				   bkey->size, cfg.capidx, cfg.dusize); | ||||||
|  | 	if (err) { | ||||||
|  | 		dev_err_ratelimited(dev, | ||||||
|  | 				    "qcom_scm_ice_set_key failed; err=%d, slot=%u\n", | ||||||
|  | 				    err, slot); | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Set CFGE after programming the key. */ | ||||||
|  | 	qcom_ice_writel(ice, le32_to_cpu(cfg.regval), | ||||||
|  | 			QCOM_ICE_REG_CRYPTOCFG(slot)); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int qcom_ice_program_key(struct qcom_ice *ice, unsigned int slot, | ||||||
|  | 			 const struct blk_crypto_key *blk_key) | ||||||
| { | { | ||||||
| 	struct device *dev = ice->dev; | 	struct device *dev = ice->dev; | ||||||
| 	union { | 	union { | ||||||
|  | @ -176,15 +352,26 @@ int qcom_ice_program_key(struct qcom_ice *ice, | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	/* Only AES-256-XTS has been tested so far. */ | 	/* Only AES-256-XTS has been tested so far. */ | ||||||
| 	if (algorithm_id != QCOM_ICE_CRYPTO_ALG_AES_XTS || | 	if (blk_key->crypto_cfg.crypto_mode != | ||||||
| 	    key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256) { | 	    BLK_ENCRYPTION_MODE_AES_256_XTS) { | ||||||
| 		dev_err_ratelimited(dev, | 		dev_err_ratelimited(dev, "Unsupported crypto mode: %d\n", | ||||||
| 				    "Unhandled crypto capability; algorithm_id=%d, key_size=%d\n", | 				    blk_key->crypto_cfg.crypto_mode); | ||||||
| 				    algorithm_id, key_size); |  | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	memcpy(key.bytes, crypto_key, AES_256_XTS_KEY_SIZE); | 	if (blk_key->crypto_cfg.key_type == BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) | ||||||
|  | 		return qcom_ice_program_wrapped_key(ice, slot, blk_key); | ||||||
|  | 
 | ||||||
|  | 	if (ice->use_hwkm) { | ||||||
|  | 		dev_err_ratelimited(dev, "Got raw key when using HWKM\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (blk_key->size != AES_256_XTS_KEY_SIZE) { | ||||||
|  | 		dev_err_ratelimited(dev, "Incorrect key size\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	memcpy(key.bytes, blk_key->bytes, AES_256_XTS_KEY_SIZE); | ||||||
| 
 | 
 | ||||||
| 	/* The SCM call requires that the key words are encoded in big endian */ | 	/* The SCM call requires that the key words are encoded in big endian */ | ||||||
| 	for (i = 0; i < ARRAY_SIZE(key.words); i++) | 	for (i = 0; i < ARRAY_SIZE(key.words); i++) | ||||||
|  | @ -192,7 +379,7 @@ int qcom_ice_program_key(struct qcom_ice *ice, | ||||||
| 
 | 
 | ||||||
| 	err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, | 	err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, | ||||||
| 				   QCOM_SCM_ICE_CIPHER_AES_256_XTS, | 				   QCOM_SCM_ICE_CIPHER_AES_256_XTS, | ||||||
| 				   data_unit_size); | 				   blk_key->crypto_cfg.data_unit_size / 512); | ||||||
| 
 | 
 | ||||||
| 	memzero_explicit(&key, sizeof(key)); | 	memzero_explicit(&key, sizeof(key)); | ||||||
| 
 | 
 | ||||||
|  | @ -202,10 +389,131 @@ EXPORT_SYMBOL_GPL(qcom_ice_program_key); | ||||||
| 
 | 
 | ||||||
| int qcom_ice_evict_key(struct qcom_ice *ice, int slot) | int qcom_ice_evict_key(struct qcom_ice *ice, int slot) | ||||||
| { | { | ||||||
|  | 	if (ice->hwkm_init_complete) | ||||||
|  | 		slot = translate_hwkm_slot(ice, slot); | ||||||
| 	return qcom_scm_ice_invalidate_key(slot); | 	return qcom_scm_ice_invalidate_key(slot); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(qcom_ice_evict_key); | EXPORT_SYMBOL_GPL(qcom_ice_evict_key); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * qcom_ice_get_supported_key_type() - Get the supported key type | ||||||
|  |  * @ice: ICE driver data | ||||||
|  |  * | ||||||
|  |  * Return: the blk-crypto key type that the ICE driver is configured to use. | ||||||
|  |  * This is the key type that ICE-capable storage drivers should advertise as | ||||||
|  |  * supported in the crypto capabilities of any disks they register. | ||||||
|  |  */ | ||||||
|  | enum blk_crypto_key_type qcom_ice_get_supported_key_type(struct qcom_ice *ice) | ||||||
|  | { | ||||||
|  | 	if (ice->use_hwkm) | ||||||
|  | 		return BLK_CRYPTO_KEY_TYPE_HW_WRAPPED; | ||||||
|  | 	return BLK_CRYPTO_KEY_TYPE_RAW; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(qcom_ice_get_supported_key_type); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * qcom_ice_derive_sw_secret() - Derive software secret from wrapped key | ||||||
|  |  * @ice: ICE driver data | ||||||
|  |  * @eph_key: an ephemerally-wrapped key | ||||||
|  |  * @eph_key_size: size of @eph_key in bytes | ||||||
|  |  * @sw_secret: output buffer for the software secret | ||||||
|  |  * | ||||||
|  |  * Use HWKM to derive the "software secret" from a hardware-wrapped key that is | ||||||
|  |  * given in ephemerally-wrapped form. | ||||||
|  |  * | ||||||
|  |  * Return: 0 on success; -EBADMSG if the given ephemerally-wrapped key is | ||||||
|  |  *	   invalid; or another -errno value. | ||||||
|  |  */ | ||||||
|  | int qcom_ice_derive_sw_secret(struct qcom_ice *ice, | ||||||
|  | 			      const u8 *eph_key, size_t eph_key_size, | ||||||
|  | 			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) | ||||||
|  | { | ||||||
|  | 	int err = qcom_scm_derive_sw_secret(eph_key, eph_key_size, | ||||||
|  | 					    sw_secret, | ||||||
|  | 					    BLK_CRYPTO_SW_SECRET_SIZE); | ||||||
|  | 	if (err == -EIO || err == -EINVAL) | ||||||
|  | 		err = -EBADMSG; /* probably invalid key */ | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(qcom_ice_derive_sw_secret); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * qcom_ice_generate_key() - Generate a wrapped key for inline encryption | ||||||
|  |  * @ice: ICE driver data | ||||||
|  |  * @lt_key: output buffer for the long-term wrapped key | ||||||
|  |  * | ||||||
|  |  * Use HWKM to generate a new key and return it as a long-term wrapped key. | ||||||
|  |  * | ||||||
|  |  * Return: the size of the resulting wrapped key on success; -errno on failure. | ||||||
|  |  */ | ||||||
|  | int qcom_ice_generate_key(struct qcom_ice *ice, | ||||||
|  | 			  u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	err = qcom_scm_generate_ice_key(lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(qcom_ice_generate_key); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * qcom_ice_prepare_key() - Prepare a wrapped key for inline encryption | ||||||
|  |  * @ice: ICE driver data | ||||||
|  |  * @lt_key: a long-term wrapped key | ||||||
|  |  * @lt_key_size: size of @lt_key in bytes | ||||||
|  |  * @eph_key: output buffer for the ephemerally-wrapped key | ||||||
|  |  * | ||||||
|  |  * Use HWKM to re-wrap a long-term wrapped key with the per-boot ephemeral key. | ||||||
|  |  * | ||||||
|  |  * Return: the size of the resulting wrapped key on success; -EBADMSG if the | ||||||
|  |  *	   given long-term wrapped key is invalid; or another -errno value. | ||||||
|  |  */ | ||||||
|  | int qcom_ice_prepare_key(struct qcom_ice *ice, | ||||||
|  | 			 const u8 *lt_key, size_t lt_key_size, | ||||||
|  | 			 u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	err = qcom_scm_prepare_ice_key(lt_key, lt_key_size, | ||||||
|  | 				       eph_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE); | ||||||
|  | 	if (err == -EIO || err == -EINVAL) | ||||||
|  | 		err = -EBADMSG; /* probably invalid key */ | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(qcom_ice_prepare_key); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * qcom_ice_import_key() - Import a raw key for inline encryption | ||||||
|  |  * @ice: ICE driver data | ||||||
|  |  * @raw_key: the raw key to import | ||||||
|  |  * @raw_key_size: size of @raw_key in bytes | ||||||
|  |  * @lt_key: output buffer for the long-term wrapped key | ||||||
|  |  * | ||||||
|  |  * Use HWKM to import a raw key and return it as a long-term wrapped key. | ||||||
|  |  * | ||||||
|  |  * Return: the size of the resulting wrapped key on success; -errno on failure. | ||||||
|  |  */ | ||||||
|  | int qcom_ice_import_key(struct qcom_ice *ice, | ||||||
|  | 			const u8 *raw_key, size_t raw_key_size, | ||||||
|  | 			u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	err = qcom_scm_import_ice_key(raw_key, raw_key_size, | ||||||
|  | 				      lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(qcom_ice_import_key); | ||||||
|  | 
 | ||||||
| static struct qcom_ice *qcom_ice_create(struct device *dev, | static struct qcom_ice *qcom_ice_create(struct device *dev, | ||||||
| 					void __iomem *base) | 					void __iomem *base) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -673,12 +673,10 @@ static ssize_t emulate_model_alias_store(struct config_item *item, | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	BUILD_BUG_ON(sizeof(dev->t10_wwn.model) != INQUIRY_MODEL_LEN + 1); | 	BUILD_BUG_ON(sizeof(dev->t10_wwn.model) != INQUIRY_MODEL_LEN + 1); | ||||||
| 	if (flag) { | 	if (flag) | ||||||
| 		dev_set_t10_wwn_model_alias(dev); | 		dev_set_t10_wwn_model_alias(dev); | ||||||
| 	} else { | 	else | ||||||
| 		strscpy(dev->t10_wwn.model, dev->transport->inquiry_prod, | 		strscpy(dev->t10_wwn.model, dev->transport->inquiry_prod); | ||||||
| 			sizeof(dev->t10_wwn.model)); |  | ||||||
| 	} |  | ||||||
| 	da->emulate_model_alias = flag; | 	da->emulate_model_alias = flag; | ||||||
| 	return count; | 	return count; | ||||||
| } | } | ||||||
|  | @ -1433,7 +1431,7 @@ static ssize_t target_wwn_vendor_id_store(struct config_item *item, | ||||||
| 	ssize_t len; | 	ssize_t len; | ||||||
| 	ssize_t ret; | 	ssize_t ret; | ||||||
| 
 | 
 | ||||||
| 	len = strscpy(buf, page, sizeof(buf)); | 	len = strscpy(buf, page); | ||||||
| 	if (len > 0) { | 	if (len > 0) { | ||||||
| 		/* Strip any newline added from userspace. */ | 		/* Strip any newline added from userspace. */ | ||||||
| 		stripped = strstrip(buf); | 		stripped = strstrip(buf); | ||||||
|  | @ -1464,7 +1462,7 @@ static ssize_t target_wwn_vendor_id_store(struct config_item *item, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BUILD_BUG_ON(sizeof(dev->t10_wwn.vendor) != INQUIRY_VENDOR_LEN + 1); | 	BUILD_BUG_ON(sizeof(dev->t10_wwn.vendor) != INQUIRY_VENDOR_LEN + 1); | ||||||
| 	strscpy(dev->t10_wwn.vendor, stripped, sizeof(dev->t10_wwn.vendor)); | 	strscpy(dev->t10_wwn.vendor, stripped); | ||||||
| 
 | 
 | ||||||
| 	pr_debug("Target_Core_ConfigFS: Set emulated T10 Vendor Identification:" | 	pr_debug("Target_Core_ConfigFS: Set emulated T10 Vendor Identification:" | ||||||
| 		 " %s\n", dev->t10_wwn.vendor); | 		 " %s\n", dev->t10_wwn.vendor); | ||||||
|  | @ -1489,7 +1487,7 @@ static ssize_t target_wwn_product_id_store(struct config_item *item, | ||||||
| 	ssize_t len; | 	ssize_t len; | ||||||
| 	ssize_t ret; | 	ssize_t ret; | ||||||
| 
 | 
 | ||||||
| 	len = strscpy(buf, page, sizeof(buf)); | 	len = strscpy(buf, page); | ||||||
| 	if (len > 0) { | 	if (len > 0) { | ||||||
| 		/* Strip any newline added from userspace. */ | 		/* Strip any newline added from userspace. */ | ||||||
| 		stripped = strstrip(buf); | 		stripped = strstrip(buf); | ||||||
|  | @ -1520,7 +1518,7 @@ static ssize_t target_wwn_product_id_store(struct config_item *item, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BUILD_BUG_ON(sizeof(dev->t10_wwn.model) != INQUIRY_MODEL_LEN + 1); | 	BUILD_BUG_ON(sizeof(dev->t10_wwn.model) != INQUIRY_MODEL_LEN + 1); | ||||||
| 	strscpy(dev->t10_wwn.model, stripped, sizeof(dev->t10_wwn.model)); | 	strscpy(dev->t10_wwn.model, stripped); | ||||||
| 
 | 
 | ||||||
| 	pr_debug("Target_Core_ConfigFS: Set emulated T10 Model Identification: %s\n", | 	pr_debug("Target_Core_ConfigFS: Set emulated T10 Model Identification: %s\n", | ||||||
| 		 dev->t10_wwn.model); | 		 dev->t10_wwn.model); | ||||||
|  | @ -1545,7 +1543,7 @@ static ssize_t target_wwn_revision_store(struct config_item *item, | ||||||
| 	ssize_t len; | 	ssize_t len; | ||||||
| 	ssize_t ret; | 	ssize_t ret; | ||||||
| 
 | 
 | ||||||
| 	len = strscpy(buf, page, sizeof(buf)); | 	len = strscpy(buf, page); | ||||||
| 	if (len > 0) { | 	if (len > 0) { | ||||||
| 		/* Strip any newline added from userspace. */ | 		/* Strip any newline added from userspace. */ | ||||||
| 		stripped = strstrip(buf); | 		stripped = strstrip(buf); | ||||||
|  | @ -1576,7 +1574,7 @@ static ssize_t target_wwn_revision_store(struct config_item *item, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BUILD_BUG_ON(sizeof(dev->t10_wwn.revision) != INQUIRY_REVISION_LEN + 1); | 	BUILD_BUG_ON(sizeof(dev->t10_wwn.revision) != INQUIRY_REVISION_LEN + 1); | ||||||
| 	strscpy(dev->t10_wwn.revision, stripped, sizeof(dev->t10_wwn.revision)); | 	strscpy(dev->t10_wwn.revision, stripped); | ||||||
| 
 | 
 | ||||||
| 	pr_debug("Target_Core_ConfigFS: Set emulated T10 Revision: %s\n", | 	pr_debug("Target_Core_ConfigFS: Set emulated T10 Revision: %s\n", | ||||||
| 		 dev->t10_wwn.revision); | 		 dev->t10_wwn.revision); | ||||||
|  |  | ||||||
|  | @ -55,14 +55,14 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd) | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	deve = target_nacl_find_deve(nacl, se_cmd->orig_fe_lun); | 	deve = target_nacl_find_deve(nacl, se_cmd->orig_fe_lun); | ||||||
| 	if (deve) { | 	if (deve) { | ||||||
| 		atomic_long_inc(&deve->total_cmds); | 		this_cpu_inc(deve->stats->total_cmds); | ||||||
| 
 | 
 | ||||||
| 		if (se_cmd->data_direction == DMA_TO_DEVICE) | 		if (se_cmd->data_direction == DMA_TO_DEVICE) | ||||||
| 			atomic_long_add(se_cmd->data_length, | 			this_cpu_add(deve->stats->write_bytes, | ||||||
| 					&deve->write_bytes); | 				     se_cmd->data_length); | ||||||
| 		else if (se_cmd->data_direction == DMA_FROM_DEVICE) | 		else if (se_cmd->data_direction == DMA_FROM_DEVICE) | ||||||
| 			atomic_long_add(se_cmd->data_length, | 			this_cpu_add(deve->stats->read_bytes, | ||||||
| 					&deve->read_bytes); | 				     se_cmd->data_length); | ||||||
| 
 | 
 | ||||||
| 		if ((se_cmd->data_direction == DMA_TO_DEVICE) && | 		if ((se_cmd->data_direction == DMA_TO_DEVICE) && | ||||||
| 		    deve->lun_access_ro) { | 		    deve->lun_access_ro) { | ||||||
|  | @ -126,14 +126,14 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd) | ||||||
| 	 * target_core_fabric_configfs.c:target_fabric_port_release | 	 * target_core_fabric_configfs.c:target_fabric_port_release | ||||||
| 	 */ | 	 */ | ||||||
| 	se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); | 	se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); | ||||||
| 	atomic_long_inc(&se_cmd->se_dev->num_cmds); | 	this_cpu_inc(se_cmd->se_dev->stats->total_cmds); | ||||||
| 
 | 
 | ||||||
| 	if (se_cmd->data_direction == DMA_TO_DEVICE) | 	if (se_cmd->data_direction == DMA_TO_DEVICE) | ||||||
| 		atomic_long_add(se_cmd->data_length, | 		this_cpu_add(se_cmd->se_dev->stats->write_bytes, | ||||||
| 				&se_cmd->se_dev->write_bytes); | 			     se_cmd->data_length); | ||||||
| 	else if (se_cmd->data_direction == DMA_FROM_DEVICE) | 	else if (se_cmd->data_direction == DMA_FROM_DEVICE) | ||||||
| 		atomic_long_add(se_cmd->data_length, | 		this_cpu_add(se_cmd->se_dev->stats->read_bytes, | ||||||
| 				&se_cmd->se_dev->read_bytes); | 			     se_cmd->data_length); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -322,6 +322,7 @@ int core_enable_device_list_for_node( | ||||||
| 	struct se_portal_group *tpg) | 	struct se_portal_group *tpg) | ||||||
| { | { | ||||||
| 	struct se_dev_entry *orig, *new; | 	struct se_dev_entry *orig, *new; | ||||||
|  | 	int ret = 0; | ||||||
| 
 | 
 | ||||||
| 	new = kzalloc(sizeof(*new), GFP_KERNEL); | 	new = kzalloc(sizeof(*new), GFP_KERNEL); | ||||||
| 	if (!new) { | 	if (!new) { | ||||||
|  | @ -329,6 +330,12 @@ int core_enable_device_list_for_node( | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	new->stats = alloc_percpu(struct se_dev_entry_io_stats); | ||||||
|  | 	if (!new->stats) { | ||||||
|  | 		ret = -ENOMEM; | ||||||
|  | 		goto free_deve; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	spin_lock_init(&new->ua_lock); | 	spin_lock_init(&new->ua_lock); | ||||||
| 	INIT_LIST_HEAD(&new->ua_list); | 	INIT_LIST_HEAD(&new->ua_list); | ||||||
| 	INIT_LIST_HEAD(&new->lun_link); | 	INIT_LIST_HEAD(&new->lun_link); | ||||||
|  | @ -351,8 +358,8 @@ int core_enable_device_list_for_node( | ||||||
| 			       " for dynamic -> explicit NodeACL conversion:" | 			       " for dynamic -> explicit NodeACL conversion:" | ||||||
| 				" %s\n", nacl->initiatorname); | 				" %s\n", nacl->initiatorname); | ||||||
| 			mutex_unlock(&nacl->lun_entry_mutex); | 			mutex_unlock(&nacl->lun_entry_mutex); | ||||||
| 			kfree(new); | 			ret = -EINVAL; | ||||||
| 			return -EINVAL; | 			goto free_stats; | ||||||
| 		} | 		} | ||||||
| 		if (orig->se_lun_acl != NULL) { | 		if (orig->se_lun_acl != NULL) { | ||||||
| 			pr_warn_ratelimited("Detected existing explicit" | 			pr_warn_ratelimited("Detected existing explicit" | ||||||
|  | @ -360,8 +367,8 @@ int core_enable_device_list_for_node( | ||||||
| 				" mapped_lun: %llu, failing\n", | 				" mapped_lun: %llu, failing\n", | ||||||
| 				 nacl->initiatorname, mapped_lun); | 				 nacl->initiatorname, mapped_lun); | ||||||
| 			mutex_unlock(&nacl->lun_entry_mutex); | 			mutex_unlock(&nacl->lun_entry_mutex); | ||||||
| 			kfree(new); | 			ret = -EINVAL; | ||||||
| 			return -EINVAL; | 			goto free_stats; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		new->se_lun = lun; | 		new->se_lun = lun; | ||||||
|  | @ -394,6 +401,20 @@ int core_enable_device_list_for_node( | ||||||
| 
 | 
 | ||||||
| 	target_luns_data_has_changed(nacl, new, true); | 	target_luns_data_has_changed(nacl, new, true); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | 
 | ||||||
|  | free_stats: | ||||||
|  | 	free_percpu(new->stats); | ||||||
|  | free_deve: | ||||||
|  | 	kfree(new); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void target_free_dev_entry(struct rcu_head *head) | ||||||
|  | { | ||||||
|  | 	struct se_dev_entry *deve = container_of(head, struct se_dev_entry, | ||||||
|  | 						 rcu_head); | ||||||
|  | 	free_percpu(deve->stats); | ||||||
|  | 	kfree(deve); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void core_disable_device_list_for_node( | void core_disable_device_list_for_node( | ||||||
|  | @ -443,7 +464,7 @@ void core_disable_device_list_for_node( | ||||||
| 	kref_put(&orig->pr_kref, target_pr_kref_release); | 	kref_put(&orig->pr_kref, target_pr_kref_release); | ||||||
| 	wait_for_completion(&orig->pr_comp); | 	wait_for_completion(&orig->pr_comp); | ||||||
| 
 | 
 | ||||||
| 	kfree_rcu(orig, rcu_head); | 	call_rcu(&orig->rcu_head, target_free_dev_entry); | ||||||
| 
 | 
 | ||||||
| 	core_scsi3_free_pr_reg_from_nacl(dev, nacl); | 	core_scsi3_free_pr_reg_from_nacl(dev, nacl); | ||||||
| 	target_luns_data_has_changed(nacl, NULL, false); | 	target_luns_data_has_changed(nacl, NULL, false); | ||||||
|  | @ -679,6 +700,18 @@ static void scsi_dump_inquiry(struct se_device *dev) | ||||||
| 	pr_debug("  Type:   %s ", scsi_device_type(device_type)); | 	pr_debug("  Type:   %s ", scsi_device_type(device_type)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void target_non_ordered_release(struct percpu_ref *ref) | ||||||
|  | { | ||||||
|  | 	struct se_device *dev = container_of(ref, struct se_device, | ||||||
|  | 					     non_ordered); | ||||||
|  | 	unsigned long flags; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&dev->delayed_cmd_lock, flags); | ||||||
|  | 	if (!list_empty(&dev->delayed_cmd_list)) | ||||||
|  | 		schedule_work(&dev->delayed_cmd_work); | ||||||
|  | 	spin_unlock_irqrestore(&dev->delayed_cmd_lock, flags); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | ||||||
| { | { | ||||||
| 	struct se_device *dev; | 	struct se_device *dev; | ||||||
|  | @ -689,11 +722,13 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | ||||||
| 	if (!dev) | 	if (!dev) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
|  | 	dev->stats = alloc_percpu(struct se_dev_io_stats); | ||||||
|  | 	if (!dev->stats) | ||||||
|  | 		goto free_device; | ||||||
|  | 
 | ||||||
| 	dev->queues = kcalloc(nr_cpu_ids, sizeof(*dev->queues), GFP_KERNEL); | 	dev->queues = kcalloc(nr_cpu_ids, sizeof(*dev->queues), GFP_KERNEL); | ||||||
| 	if (!dev->queues) { | 	if (!dev->queues) | ||||||
| 		hba->backend->ops->free_device(dev); | 		goto free_stats; | ||||||
| 		return NULL; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	dev->queue_cnt = nr_cpu_ids; | 	dev->queue_cnt = nr_cpu_ids; | ||||||
| 	for (i = 0; i < dev->queue_cnt; i++) { | 	for (i = 0; i < dev->queue_cnt; i++) { | ||||||
|  | @ -707,6 +742,10 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | ||||||
| 		INIT_WORK(&q->sq.work, target_queued_submit_work); | 		INIT_WORK(&q->sq.work, target_queued_submit_work); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (percpu_ref_init(&dev->non_ordered, target_non_ordered_release, | ||||||
|  | 			    PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) | ||||||
|  | 		goto free_queues; | ||||||
|  | 
 | ||||||
| 	dev->se_hba = hba; | 	dev->se_hba = hba; | ||||||
| 	dev->transport = hba->backend->ops; | 	dev->transport = hba->backend->ops; | ||||||
| 	dev->transport_flags = dev->transport->transport_flags_default; | 	dev->transport_flags = dev->transport->transport_flags_default; | ||||||
|  | @ -791,6 +830,14 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | ||||||
| 		sizeof(dev->t10_wwn.revision)); | 		sizeof(dev->t10_wwn.revision)); | ||||||
| 
 | 
 | ||||||
| 	return dev; | 	return dev; | ||||||
|  | 
 | ||||||
|  | free_queues: | ||||||
|  | 	kfree(dev->queues); | ||||||
|  | free_stats: | ||||||
|  | 	free_percpu(dev->stats); | ||||||
|  | free_device: | ||||||
|  | 	hba->backend->ops->free_device(dev); | ||||||
|  | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -980,6 +1027,9 @@ void target_free_device(struct se_device *dev) | ||||||
| 
 | 
 | ||||||
| 	WARN_ON(!list_empty(&dev->dev_sep_list)); | 	WARN_ON(!list_empty(&dev->dev_sep_list)); | ||||||
| 
 | 
 | ||||||
|  | 	percpu_ref_exit(&dev->non_ordered); | ||||||
|  | 	cancel_work_sync(&dev->delayed_cmd_work); | ||||||
|  | 
 | ||||||
| 	if (target_dev_configured(dev)) { | 	if (target_dev_configured(dev)) { | ||||||
| 		dev->transport->destroy_device(dev); | 		dev->transport->destroy_device(dev); | ||||||
| 
 | 
 | ||||||
|  | @ -1001,6 +1051,7 @@ void target_free_device(struct se_device *dev) | ||||||
| 		dev->transport->free_prot(dev); | 		dev->transport->free_prot(dev); | ||||||
| 
 | 
 | ||||||
| 	kfree(dev->queues); | 	kfree(dev->queues); | ||||||
|  | 	free_percpu(dev->stats); | ||||||
| 	dev->transport->free_device(dev); | 	dev->transport->free_device(dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1325,7 +1325,7 @@ static void set_dpofua_usage_bits32(u8 *usage_bits, struct se_device *dev) | ||||||
| 		usage_bits[10] |= 0x18; | 		usage_bits[10] |= 0x18; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_read6 = { | static const struct target_opcode_descriptor tcm_opcode_read6 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = READ_6, | 	.opcode = READ_6, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1333,7 +1333,7 @@ static struct target_opcode_descriptor tcm_opcode_read6 = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_read10 = { | static const struct target_opcode_descriptor tcm_opcode_read10 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = READ_10, | 	.opcode = READ_10, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1343,7 +1343,7 @@ static struct target_opcode_descriptor tcm_opcode_read10 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_read12 = { | static const struct target_opcode_descriptor tcm_opcode_read12 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = READ_12, | 	.opcode = READ_12, | ||||||
| 	.cdb_size = 12, | 	.cdb_size = 12, | ||||||
|  | @ -1353,7 +1353,7 @@ static struct target_opcode_descriptor tcm_opcode_read12 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_read16 = { | static const struct target_opcode_descriptor tcm_opcode_read16 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = READ_16, | 	.opcode = READ_16, | ||||||
| 	.cdb_size = 16, | 	.cdb_size = 16, | ||||||
|  | @ -1364,7 +1364,7 @@ static struct target_opcode_descriptor tcm_opcode_read16 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write6 = { | static const struct target_opcode_descriptor tcm_opcode_write6 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_6, | 	.opcode = WRITE_6, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1372,7 +1372,7 @@ static struct target_opcode_descriptor tcm_opcode_write6 = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write10 = { | static const struct target_opcode_descriptor tcm_opcode_write10 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_10, | 	.opcode = WRITE_10, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1382,7 +1382,7 @@ static struct target_opcode_descriptor tcm_opcode_write10 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write_verify10 = { | static const struct target_opcode_descriptor tcm_opcode_write_verify10 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_VERIFY, | 	.opcode = WRITE_VERIFY, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1392,7 +1392,7 @@ static struct target_opcode_descriptor tcm_opcode_write_verify10 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write12 = { | static const struct target_opcode_descriptor tcm_opcode_write12 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_12, | 	.opcode = WRITE_12, | ||||||
| 	.cdb_size = 12, | 	.cdb_size = 12, | ||||||
|  | @ -1402,7 +1402,7 @@ static struct target_opcode_descriptor tcm_opcode_write12 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write16 = { | static const struct target_opcode_descriptor tcm_opcode_write16 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_16, | 	.opcode = WRITE_16, | ||||||
| 	.cdb_size = 16, | 	.cdb_size = 16, | ||||||
|  | @ -1413,7 +1413,7 @@ static struct target_opcode_descriptor tcm_opcode_write16 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write_verify16 = { | static const struct target_opcode_descriptor tcm_opcode_write_verify16 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_VERIFY_16, | 	.opcode = WRITE_VERIFY_16, | ||||||
| 	.cdb_size = 16, | 	.cdb_size = 16, | ||||||
|  | @ -1424,7 +1424,7 @@ static struct target_opcode_descriptor tcm_opcode_write_verify16 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool tcm_is_ws_enabled(struct target_opcode_descriptor *descr, | static bool tcm_is_ws_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 			      struct se_cmd *cmd) | 			      struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct exec_cmd_ops *ops = cmd->protocol_data; | 	struct exec_cmd_ops *ops = cmd->protocol_data; | ||||||
|  | @ -1434,7 +1434,7 @@ static bool tcm_is_ws_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	       !!ops->execute_write_same; | 	       !!ops->execute_write_same; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write_same32 = { | static const struct target_opcode_descriptor tcm_opcode_write_same32 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = VARIABLE_LENGTH_CMD, | 	.opcode = VARIABLE_LENGTH_CMD, | ||||||
|  | @ -1452,7 +1452,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same32 = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits32, | 	.update_usage_bits = set_dpofua_usage_bits32, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool tcm_is_caw_enabled(struct target_opcode_descriptor *descr, | static bool tcm_is_caw_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 			       struct se_cmd *cmd) | 			       struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct se_device *dev = cmd->se_dev; | 	struct se_device *dev = cmd->se_dev; | ||||||
|  | @ -1460,7 +1460,7 @@ static bool tcm_is_caw_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	return dev->dev_attrib.emulate_caw; | 	return dev->dev_attrib.emulate_caw; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_compare_write = { | static const struct target_opcode_descriptor tcm_opcode_compare_write = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = COMPARE_AND_WRITE, | 	.opcode = COMPARE_AND_WRITE, | ||||||
| 	.cdb_size = 16, | 	.cdb_size = 16, | ||||||
|  | @ -1472,7 +1472,7 @@ static struct target_opcode_descriptor tcm_opcode_compare_write = { | ||||||
| 	.update_usage_bits = set_dpofua_usage_bits, | 	.update_usage_bits = set_dpofua_usage_bits, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_read_capacity = { | static const struct target_opcode_descriptor tcm_opcode_read_capacity = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = READ_CAPACITY, | 	.opcode = READ_CAPACITY, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1481,7 +1481,7 @@ static struct target_opcode_descriptor tcm_opcode_read_capacity = { | ||||||
| 		       0x01, SCSI_CONTROL_MASK}, | 		       0x01, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_read_capacity16 = { | static const struct target_opcode_descriptor tcm_opcode_read_capacity16 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = SERVICE_ACTION_IN_16, | 	.opcode = SERVICE_ACTION_IN_16, | ||||||
|  | @ -1493,7 +1493,7 @@ static struct target_opcode_descriptor tcm_opcode_read_capacity16 = { | ||||||
| 		       0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, | 		       0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool tcm_is_rep_ref_enabled(struct target_opcode_descriptor *descr, | static bool tcm_is_rep_ref_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 				   struct se_cmd *cmd) | 				   struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct se_device *dev = cmd->se_dev; | 	struct se_device *dev = cmd->se_dev; | ||||||
|  | @ -1507,7 +1507,7 @@ static bool tcm_is_rep_ref_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_read_report_refferals = { | static const struct target_opcode_descriptor tcm_opcode_read_report_refferals = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = SERVICE_ACTION_IN_16, | 	.opcode = SERVICE_ACTION_IN_16, | ||||||
|  | @ -1520,7 +1520,7 @@ static struct target_opcode_descriptor tcm_opcode_read_report_refferals = { | ||||||
| 	.enabled = tcm_is_rep_ref_enabled, | 	.enabled = tcm_is_rep_ref_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_sync_cache = { | static const struct target_opcode_descriptor tcm_opcode_sync_cache = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = SYNCHRONIZE_CACHE, | 	.opcode = SYNCHRONIZE_CACHE, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1529,7 +1529,7 @@ static struct target_opcode_descriptor tcm_opcode_sync_cache = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_sync_cache16 = { | static const struct target_opcode_descriptor tcm_opcode_sync_cache16 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = SYNCHRONIZE_CACHE_16, | 	.opcode = SYNCHRONIZE_CACHE_16, | ||||||
| 	.cdb_size = 16, | 	.cdb_size = 16, | ||||||
|  | @ -1539,7 +1539,7 @@ static struct target_opcode_descriptor tcm_opcode_sync_cache16 = { | ||||||
| 		       0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, | 		       0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool tcm_is_unmap_enabled(struct target_opcode_descriptor *descr, | static bool tcm_is_unmap_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 				 struct se_cmd *cmd) | 				 struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct exec_cmd_ops *ops = cmd->protocol_data; | 	struct exec_cmd_ops *ops = cmd->protocol_data; | ||||||
|  | @ -1548,7 +1548,7 @@ static bool tcm_is_unmap_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	return ops->execute_unmap && dev->dev_attrib.emulate_tpu; | 	return ops->execute_unmap && dev->dev_attrib.emulate_tpu; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_unmap = { | static const struct target_opcode_descriptor tcm_opcode_unmap = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = UNMAP, | 	.opcode = UNMAP, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1558,7 +1558,7 @@ static struct target_opcode_descriptor tcm_opcode_unmap = { | ||||||
| 	.enabled = tcm_is_unmap_enabled, | 	.enabled = tcm_is_unmap_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write_same = { | static const struct target_opcode_descriptor tcm_opcode_write_same = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_SAME, | 	.opcode = WRITE_SAME, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1568,7 +1568,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same = { | ||||||
| 	.enabled = tcm_is_ws_enabled, | 	.enabled = tcm_is_ws_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_write_same16 = { | static const struct target_opcode_descriptor tcm_opcode_write_same16 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = WRITE_SAME_16, | 	.opcode = WRITE_SAME_16, | ||||||
| 	.cdb_size = 16, | 	.cdb_size = 16, | ||||||
|  | @ -1579,7 +1579,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same16 = { | ||||||
| 	.enabled = tcm_is_ws_enabled, | 	.enabled = tcm_is_ws_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_verify = { | static const struct target_opcode_descriptor tcm_opcode_verify = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = VERIFY, | 	.opcode = VERIFY, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1588,7 +1588,7 @@ static struct target_opcode_descriptor tcm_opcode_verify = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_verify16 = { | static const struct target_opcode_descriptor tcm_opcode_verify16 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = VERIFY_16, | 	.opcode = VERIFY_16, | ||||||
| 	.cdb_size = 16, | 	.cdb_size = 16, | ||||||
|  | @ -1598,7 +1598,7 @@ static struct target_opcode_descriptor tcm_opcode_verify16 = { | ||||||
| 		       0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, | 		       0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_start_stop = { | static const struct target_opcode_descriptor tcm_opcode_start_stop = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = START_STOP, | 	.opcode = START_STOP, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1606,7 +1606,7 @@ static struct target_opcode_descriptor tcm_opcode_start_stop = { | ||||||
| 		       0x01, SCSI_CONTROL_MASK}, | 		       0x01, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_mode_select = { | static const struct target_opcode_descriptor tcm_opcode_mode_select = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = MODE_SELECT, | 	.opcode = MODE_SELECT, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1614,7 +1614,7 @@ static struct target_opcode_descriptor tcm_opcode_mode_select = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_mode_select10 = { | static const struct target_opcode_descriptor tcm_opcode_mode_select10 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = MODE_SELECT_10, | 	.opcode = MODE_SELECT_10, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1623,7 +1623,7 @@ static struct target_opcode_descriptor tcm_opcode_mode_select10 = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_mode_sense = { | static const struct target_opcode_descriptor tcm_opcode_mode_sense = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = MODE_SENSE, | 	.opcode = MODE_SENSE, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1631,7 +1631,7 @@ static struct target_opcode_descriptor tcm_opcode_mode_sense = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_mode_sense10 = { | static const struct target_opcode_descriptor tcm_opcode_mode_sense10 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = MODE_SENSE_10, | 	.opcode = MODE_SENSE_10, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1640,7 +1640,7 @@ static struct target_opcode_descriptor tcm_opcode_mode_sense10 = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pri_read_keys = { | static const struct target_opcode_descriptor tcm_opcode_pri_read_keys = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_IN, | 	.opcode = PERSISTENT_RESERVE_IN, | ||||||
|  | @ -1651,7 +1651,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_keys = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pri_read_resrv = { | static const struct target_opcode_descriptor tcm_opcode_pri_read_resrv = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_IN, | 	.opcode = PERSISTENT_RESERVE_IN, | ||||||
|  | @ -1662,7 +1662,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_resrv = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool tcm_is_pr_enabled(struct target_opcode_descriptor *descr, | static bool tcm_is_pr_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 			      struct se_cmd *cmd) | 			      struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct se_device *dev = cmd->se_dev; | 	struct se_device *dev = cmd->se_dev; | ||||||
|  | @ -1704,7 +1704,7 @@ static bool tcm_is_pr_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pri_read_caps = { | static const struct target_opcode_descriptor tcm_opcode_pri_read_caps = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_IN, | 	.opcode = PERSISTENT_RESERVE_IN, | ||||||
|  | @ -1716,7 +1716,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_caps = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = { | static const struct target_opcode_descriptor tcm_opcode_pri_read_full_status = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_IN, | 	.opcode = PERSISTENT_RESERVE_IN, | ||||||
|  | @ -1728,7 +1728,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_register = { | static const struct target_opcode_descriptor tcm_opcode_pro_register = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1740,7 +1740,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_register = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_reserve = { | static const struct target_opcode_descriptor tcm_opcode_pro_reserve = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1752,7 +1752,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_reserve = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_release = { | static const struct target_opcode_descriptor tcm_opcode_pro_release = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1764,7 +1764,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_release = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_clear = { | static const struct target_opcode_descriptor tcm_opcode_pro_clear = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1776,7 +1776,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_clear = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_preempt = { | static const struct target_opcode_descriptor tcm_opcode_pro_preempt = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1788,7 +1788,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_preempt = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = { | static const struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1800,7 +1800,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = { | static const struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1814,7 +1814,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_pro_register_move = { | static const struct target_opcode_descriptor tcm_opcode_pro_register_move = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = PERSISTENT_RESERVE_OUT, | 	.opcode = PERSISTENT_RESERVE_OUT, | ||||||
|  | @ -1826,7 +1826,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_register_move = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_release = { | static const struct target_opcode_descriptor tcm_opcode_release = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = RELEASE_6, | 	.opcode = RELEASE_6, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1835,7 +1835,7 @@ static struct target_opcode_descriptor tcm_opcode_release = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_release10 = { | static const struct target_opcode_descriptor tcm_opcode_release10 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = RELEASE_10, | 	.opcode = RELEASE_10, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1845,7 +1845,7 @@ static struct target_opcode_descriptor tcm_opcode_release10 = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_reserve = { | static const struct target_opcode_descriptor tcm_opcode_reserve = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = RESERVE_6, | 	.opcode = RESERVE_6, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1854,7 +1854,7 @@ static struct target_opcode_descriptor tcm_opcode_reserve = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_reserve10 = { | static const struct target_opcode_descriptor tcm_opcode_reserve10 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = RESERVE_10, | 	.opcode = RESERVE_10, | ||||||
| 	.cdb_size = 10, | 	.cdb_size = 10, | ||||||
|  | @ -1864,7 +1864,7 @@ static struct target_opcode_descriptor tcm_opcode_reserve10 = { | ||||||
| 	.enabled = tcm_is_pr_enabled, | 	.enabled = tcm_is_pr_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_request_sense = { | static const struct target_opcode_descriptor tcm_opcode_request_sense = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = REQUEST_SENSE, | 	.opcode = REQUEST_SENSE, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1872,7 +1872,7 @@ static struct target_opcode_descriptor tcm_opcode_request_sense = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_inquiry = { | static const struct target_opcode_descriptor tcm_opcode_inquiry = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = INQUIRY, | 	.opcode = INQUIRY, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1880,7 +1880,7 @@ static struct target_opcode_descriptor tcm_opcode_inquiry = { | ||||||
| 		       0xff, SCSI_CONTROL_MASK}, | 		       0xff, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool tcm_is_3pc_enabled(struct target_opcode_descriptor *descr, | static bool tcm_is_3pc_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 			       struct se_cmd *cmd) | 			       struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct se_device *dev = cmd->se_dev; | 	struct se_device *dev = cmd->se_dev; | ||||||
|  | @ -1888,7 +1888,7 @@ static bool tcm_is_3pc_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	return dev->dev_attrib.emulate_3pc; | 	return dev->dev_attrib.emulate_3pc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = { | static const struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = EXTENDED_COPY, | 	.opcode = EXTENDED_COPY, | ||||||
|  | @ -1900,7 +1900,7 @@ static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = { | ||||||
| 	.enabled = tcm_is_3pc_enabled, | 	.enabled = tcm_is_3pc_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = { | static const struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = RECEIVE_COPY_RESULTS, | 	.opcode = RECEIVE_COPY_RESULTS, | ||||||
|  | @ -1914,7 +1914,7 @@ static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = { | ||||||
| 	.enabled = tcm_is_3pc_enabled, | 	.enabled = tcm_is_3pc_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_report_luns = { | static const struct target_opcode_descriptor tcm_opcode_report_luns = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = REPORT_LUNS, | 	.opcode = REPORT_LUNS, | ||||||
| 	.cdb_size = 12, | 	.cdb_size = 12, | ||||||
|  | @ -1923,7 +1923,7 @@ static struct target_opcode_descriptor tcm_opcode_report_luns = { | ||||||
| 		       0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, | 		       0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_test_unit_ready = { | static const struct target_opcode_descriptor tcm_opcode_test_unit_ready = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.opcode = TEST_UNIT_READY, | 	.opcode = TEST_UNIT_READY, | ||||||
| 	.cdb_size = 6, | 	.cdb_size = 6, | ||||||
|  | @ -1931,7 +1931,7 @@ static struct target_opcode_descriptor tcm_opcode_test_unit_ready = { | ||||||
| 		       0x00, SCSI_CONTROL_MASK}, | 		       0x00, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_report_target_pgs = { | static const struct target_opcode_descriptor tcm_opcode_report_target_pgs = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = MAINTENANCE_IN, | 	.opcode = MAINTENANCE_IN, | ||||||
|  | @ -1942,7 +1942,7 @@ static struct target_opcode_descriptor tcm_opcode_report_target_pgs = { | ||||||
| 		       0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, | 		       0xff, 0xff, 0x00, SCSI_CONTROL_MASK}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool spc_rsoc_enabled(struct target_opcode_descriptor *descr, | static bool spc_rsoc_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 			     struct se_cmd *cmd) | 			     struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct se_device *dev = cmd->se_dev; | 	struct se_device *dev = cmd->se_dev; | ||||||
|  | @ -1950,7 +1950,7 @@ static bool spc_rsoc_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	return dev->dev_attrib.emulate_rsoc; | 	return dev->dev_attrib.emulate_rsoc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { | static const struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = MAINTENANCE_IN, | 	.opcode = MAINTENANCE_IN, | ||||||
|  | @ -1963,7 +1963,7 @@ static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { | ||||||
| 	.enabled = spc_rsoc_enabled, | 	.enabled = spc_rsoc_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static bool tcm_is_set_tpg_enabled(struct target_opcode_descriptor *descr, | static bool tcm_is_set_tpg_enabled(const struct target_opcode_descriptor *descr, | ||||||
| 				   struct se_cmd *cmd) | 				   struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct t10_alua_tg_pt_gp *l_tg_pt_gp; | 	struct t10_alua_tg_pt_gp *l_tg_pt_gp; | ||||||
|  | @ -1984,7 +1984,7 @@ static bool tcm_is_set_tpg_enabled(struct target_opcode_descriptor *descr, | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor tcm_opcode_set_tpg = { | static const struct target_opcode_descriptor tcm_opcode_set_tpg = { | ||||||
| 	.support = SCSI_SUPPORT_FULL, | 	.support = SCSI_SUPPORT_FULL, | ||||||
| 	.serv_action_valid = 1, | 	.serv_action_valid = 1, | ||||||
| 	.opcode = MAINTENANCE_OUT, | 	.opcode = MAINTENANCE_OUT, | ||||||
|  | @ -1996,7 +1996,7 @@ static struct target_opcode_descriptor tcm_opcode_set_tpg = { | ||||||
| 	.enabled = tcm_is_set_tpg_enabled, | 	.enabled = tcm_is_set_tpg_enabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct target_opcode_descriptor *tcm_supported_opcodes[] = { | static const struct target_opcode_descriptor *tcm_supported_opcodes[] = { | ||||||
| 	&tcm_opcode_read6, | 	&tcm_opcode_read6, | ||||||
| 	&tcm_opcode_read10, | 	&tcm_opcode_read10, | ||||||
| 	&tcm_opcode_read12, | 	&tcm_opcode_read12, | ||||||
|  | @ -2053,7 +2053,7 @@ static struct target_opcode_descriptor *tcm_supported_opcodes[] = { | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| spc_rsoc_encode_command_timeouts_descriptor(unsigned char *buf, u8 ctdp, | spc_rsoc_encode_command_timeouts_descriptor(unsigned char *buf, u8 ctdp, | ||||||
| 				struct target_opcode_descriptor *descr) | 				const struct target_opcode_descriptor *descr) | ||||||
| { | { | ||||||
| 	if (!ctdp) | 	if (!ctdp) | ||||||
| 		return 0; | 		return 0; | ||||||
|  | @ -2068,7 +2068,7 @@ spc_rsoc_encode_command_timeouts_descriptor(unsigned char *buf, u8 ctdp, | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| spc_rsoc_encode_command_descriptor(unsigned char *buf, u8 ctdp, | spc_rsoc_encode_command_descriptor(unsigned char *buf, u8 ctdp, | ||||||
| 				   struct target_opcode_descriptor *descr) | 				   const struct target_opcode_descriptor *descr) | ||||||
| { | { | ||||||
| 	int td_size = 0; | 	int td_size = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -2087,7 +2087,7 @@ spc_rsoc_encode_command_descriptor(unsigned char *buf, u8 ctdp, | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp, | spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp, | ||||||
| 				       struct target_opcode_descriptor *descr, | 				       const struct target_opcode_descriptor *descr, | ||||||
| 				       struct se_device *dev) | 				       struct se_device *dev) | ||||||
| { | { | ||||||
| 	int td_size = 0; | 	int td_size = 0; | ||||||
|  | @ -2110,9 +2110,9 @@ spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static sense_reason_t | static sense_reason_t | ||||||
| spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) | spc_rsoc_get_descr(struct se_cmd *cmd, const struct target_opcode_descriptor **opcode) | ||||||
| { | { | ||||||
| 	struct target_opcode_descriptor *descr; | 	const struct target_opcode_descriptor *descr; | ||||||
| 	struct se_session *sess = cmd->se_sess; | 	struct se_session *sess = cmd->se_sess; | ||||||
| 	unsigned char *cdb = cmd->t_task_cdb; | 	unsigned char *cdb = cmd->t_task_cdb; | ||||||
| 	u8 opts = cdb[2] & 0x3; | 	u8 opts = cdb[2] & 0x3; | ||||||
|  | @ -2199,7 +2199,7 @@ static sense_reason_t | ||||||
| spc_emulate_report_supp_op_codes(struct se_cmd *cmd) | spc_emulate_report_supp_op_codes(struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	int descr_num = ARRAY_SIZE(tcm_supported_opcodes); | 	int descr_num = ARRAY_SIZE(tcm_supported_opcodes); | ||||||
| 	struct target_opcode_descriptor *descr = NULL; | 	const struct target_opcode_descriptor *descr = NULL; | ||||||
| 	unsigned char *cdb = cmd->t_task_cdb; | 	unsigned char *cdb = cmd->t_task_cdb; | ||||||
| 	u8 rctd = (cdb[2] >> 7) & 0x1; | 	u8 rctd = (cdb[2] >> 7) & 0x1; | ||||||
| 	unsigned char *buf = NULL; | 	unsigned char *buf = NULL; | ||||||
|  |  | ||||||
|  | @ -280,30 +280,51 @@ static ssize_t target_stat_lu_num_cmds_show(struct config_item *item, | ||||||
| 		char *page) | 		char *page) | ||||||
| { | { | ||||||
| 	struct se_device *dev = to_stat_lu_dev(item); | 	struct se_device *dev = to_stat_lu_dev(item); | ||||||
|  | 	struct se_dev_io_stats *stats; | ||||||
|  | 	unsigned int cpu; | ||||||
|  | 	u32 cmds = 0; | ||||||
|  | 
 | ||||||
|  | 	for_each_possible_cpu(cpu) { | ||||||
|  | 		stats = per_cpu_ptr(dev->stats, cpu); | ||||||
|  | 		cmds += stats->total_cmds; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* scsiLuNumCommands */ | 	/* scsiLuNumCommands */ | ||||||
| 	return snprintf(page, PAGE_SIZE, "%lu\n", | 	return snprintf(page, PAGE_SIZE, "%u\n", cmds); | ||||||
| 			atomic_long_read(&dev->num_cmds)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item, | static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item, | ||||||
| 		char *page) | 		char *page) | ||||||
| { | { | ||||||
| 	struct se_device *dev = to_stat_lu_dev(item); | 	struct se_device *dev = to_stat_lu_dev(item); | ||||||
|  | 	struct se_dev_io_stats *stats; | ||||||
|  | 	unsigned int cpu; | ||||||
|  | 	u32 bytes = 0; | ||||||
|  | 
 | ||||||
|  | 	for_each_possible_cpu(cpu) { | ||||||
|  | 		stats = per_cpu_ptr(dev->stats, cpu); | ||||||
|  | 		bytes += stats->read_bytes; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* scsiLuReadMegaBytes */ | 	/* scsiLuReadMegaBytes */ | ||||||
| 	return snprintf(page, PAGE_SIZE, "%lu\n", | 	return snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); | ||||||
| 			atomic_long_read(&dev->read_bytes) >> 20); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item, | static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item, | ||||||
| 		char *page) | 		char *page) | ||||||
| { | { | ||||||
| 	struct se_device *dev = to_stat_lu_dev(item); | 	struct se_device *dev = to_stat_lu_dev(item); | ||||||
|  | 	struct se_dev_io_stats *stats; | ||||||
|  | 	unsigned int cpu; | ||||||
|  | 	u32 bytes = 0; | ||||||
|  | 
 | ||||||
|  | 	for_each_possible_cpu(cpu) { | ||||||
|  | 		stats = per_cpu_ptr(dev->stats, cpu); | ||||||
|  | 		bytes += stats->write_bytes; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* scsiLuWrittenMegaBytes */ | 	/* scsiLuWrittenMegaBytes */ | ||||||
| 	return snprintf(page, PAGE_SIZE, "%lu\n", | 	return snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); | ||||||
| 			atomic_long_read(&dev->write_bytes) >> 20); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t target_stat_lu_resets_show(struct config_item *item, char *page) | static ssize_t target_stat_lu_resets_show(struct config_item *item, char *page) | ||||||
|  | @ -1019,8 +1040,11 @@ static ssize_t target_stat_auth_num_cmds_show(struct config_item *item, | ||||||
| { | { | ||||||
| 	struct se_lun_acl *lacl = auth_to_lacl(item); | 	struct se_lun_acl *lacl = auth_to_lacl(item); | ||||||
| 	struct se_node_acl *nacl = lacl->se_lun_nacl; | 	struct se_node_acl *nacl = lacl->se_lun_nacl; | ||||||
|  | 	struct se_dev_entry_io_stats *stats; | ||||||
| 	struct se_dev_entry *deve; | 	struct se_dev_entry *deve; | ||||||
|  | 	unsigned int cpu; | ||||||
| 	ssize_t ret; | 	ssize_t ret; | ||||||
|  | 	u32 cmds = 0; | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	deve = target_nacl_find_deve(nacl, lacl->mapped_lun); | 	deve = target_nacl_find_deve(nacl, lacl->mapped_lun); | ||||||
|  | @ -1028,9 +1052,14 @@ static ssize_t target_stat_auth_num_cmds_show(struct config_item *item, | ||||||
| 		rcu_read_unlock(); | 		rcu_read_unlock(); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	for_each_possible_cpu(cpu) { | ||||||
|  | 		stats = per_cpu_ptr(deve->stats, cpu); | ||||||
|  | 		cmds += stats->total_cmds; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* scsiAuthIntrOutCommands */ | 	/* scsiAuthIntrOutCommands */ | ||||||
| 	ret = snprintf(page, PAGE_SIZE, "%lu\n", | 	ret = snprintf(page, PAGE_SIZE, "%u\n", cmds); | ||||||
| 		       atomic_long_read(&deve->total_cmds)); |  | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -1040,8 +1069,11 @@ static ssize_t target_stat_auth_read_mbytes_show(struct config_item *item, | ||||||
| { | { | ||||||
| 	struct se_lun_acl *lacl = auth_to_lacl(item); | 	struct se_lun_acl *lacl = auth_to_lacl(item); | ||||||
| 	struct se_node_acl *nacl = lacl->se_lun_nacl; | 	struct se_node_acl *nacl = lacl->se_lun_nacl; | ||||||
|  | 	struct se_dev_entry_io_stats *stats; | ||||||
| 	struct se_dev_entry *deve; | 	struct se_dev_entry *deve; | ||||||
|  | 	unsigned int cpu; | ||||||
| 	ssize_t ret; | 	ssize_t ret; | ||||||
|  | 	u32 bytes = 0; | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	deve = target_nacl_find_deve(nacl, lacl->mapped_lun); | 	deve = target_nacl_find_deve(nacl, lacl->mapped_lun); | ||||||
|  | @ -1049,9 +1081,14 @@ static ssize_t target_stat_auth_read_mbytes_show(struct config_item *item, | ||||||
| 		rcu_read_unlock(); | 		rcu_read_unlock(); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	for_each_possible_cpu(cpu) { | ||||||
|  | 		stats = per_cpu_ptr(deve->stats, cpu); | ||||||
|  | 		bytes += stats->read_bytes; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* scsiAuthIntrReadMegaBytes */ | 	/* scsiAuthIntrReadMegaBytes */ | ||||||
| 	ret = snprintf(page, PAGE_SIZE, "%u\n", | 	ret = snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); | ||||||
| 		      (u32)(atomic_long_read(&deve->read_bytes) >> 20)); |  | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -1061,8 +1098,11 @@ static ssize_t target_stat_auth_write_mbytes_show(struct config_item *item, | ||||||
| { | { | ||||||
| 	struct se_lun_acl *lacl = auth_to_lacl(item); | 	struct se_lun_acl *lacl = auth_to_lacl(item); | ||||||
| 	struct se_node_acl *nacl = lacl->se_lun_nacl; | 	struct se_node_acl *nacl = lacl->se_lun_nacl; | ||||||
|  | 	struct se_dev_entry_io_stats *stats; | ||||||
| 	struct se_dev_entry *deve; | 	struct se_dev_entry *deve; | ||||||
|  | 	unsigned int cpu; | ||||||
| 	ssize_t ret; | 	ssize_t ret; | ||||||
|  | 	u32 bytes = 0; | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	deve = target_nacl_find_deve(nacl, lacl->mapped_lun); | 	deve = target_nacl_find_deve(nacl, lacl->mapped_lun); | ||||||
|  | @ -1070,9 +1110,14 @@ static ssize_t target_stat_auth_write_mbytes_show(struct config_item *item, | ||||||
| 		rcu_read_unlock(); | 		rcu_read_unlock(); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	for_each_possible_cpu(cpu) { | ||||||
|  | 		stats = per_cpu_ptr(deve->stats, cpu); | ||||||
|  | 		bytes += stats->write_bytes; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* scsiAuthIntrWrittenMegaBytes */ | 	/* scsiAuthIntrWrittenMegaBytes */ | ||||||
| 	ret = snprintf(page, PAGE_SIZE, "%u\n", | 	ret = snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20); | ||||||
| 		      (u32)(atomic_long_read(&deve->write_bytes) >> 20)); |  | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2213,6 +2213,7 @@ static int target_write_prot_action(struct se_cmd *cmd) | ||||||
| static bool target_handle_task_attr(struct se_cmd *cmd) | static bool target_handle_task_attr(struct se_cmd *cmd) | ||||||
| { | { | ||||||
| 	struct se_device *dev = cmd->se_dev; | 	struct se_device *dev = cmd->se_dev; | ||||||
|  | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
| 	if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) | 	if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -2225,13 +2226,10 @@ static bool target_handle_task_attr(struct se_cmd *cmd) | ||||||
| 	 */ | 	 */ | ||||||
| 	switch (cmd->sam_task_attr) { | 	switch (cmd->sam_task_attr) { | ||||||
| 	case TCM_HEAD_TAG: | 	case TCM_HEAD_TAG: | ||||||
| 		atomic_inc_mb(&dev->non_ordered); |  | ||||||
| 		pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x\n", | 		pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x\n", | ||||||
| 			 cmd->t_task_cdb[0]); | 			 cmd->t_task_cdb[0]); | ||||||
| 		return false; | 		return false; | ||||||
| 	case TCM_ORDERED_TAG: | 	case TCM_ORDERED_TAG: | ||||||
| 		atomic_inc_mb(&dev->delayed_cmd_count); |  | ||||||
| 
 |  | ||||||
| 		pr_debug("Added ORDERED for CDB: 0x%02x to ordered list\n", | 		pr_debug("Added ORDERED for CDB: 0x%02x to ordered list\n", | ||||||
| 			 cmd->t_task_cdb[0]); | 			 cmd->t_task_cdb[0]); | ||||||
| 		break; | 		break; | ||||||
|  | @ -2239,29 +2237,29 @@ static bool target_handle_task_attr(struct se_cmd *cmd) | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * For SIMPLE and UNTAGGED Task Attribute commands | 		 * For SIMPLE and UNTAGGED Task Attribute commands | ||||||
| 		 */ | 		 */ | ||||||
| 		atomic_inc_mb(&dev->non_ordered); | retry: | ||||||
| 
 | 		if (percpu_ref_tryget_live(&dev->non_ordered)) | ||||||
| 		if (atomic_read(&dev->delayed_cmd_count) == 0) |  | ||||||
| 			return false; | 			return false; | ||||||
|  | 
 | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (cmd->sam_task_attr != TCM_ORDERED_TAG) { | 	spin_lock_irqsave(&dev->delayed_cmd_lock, flags); | ||||||
| 		atomic_inc_mb(&dev->delayed_cmd_count); | 	if (cmd->sam_task_attr == TCM_SIMPLE_TAG && | ||||||
| 		/*
 | 	    !percpu_ref_is_dying(&dev->non_ordered)) { | ||||||
| 		 * We will account for this when we dequeue from the delayed | 		spin_unlock_irqrestore(&dev->delayed_cmd_lock, flags); | ||||||
| 		 * list. | 		/* We raced with the last ordered completion so retry. */ | ||||||
| 		 */ | 		goto retry; | ||||||
| 		atomic_dec_mb(&dev->non_ordered); | 	} else if (!percpu_ref_is_dying(&dev->non_ordered)) { | ||||||
|  | 		percpu_ref_kill(&dev->non_ordered); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irq(&cmd->t_state_lock); | 	spin_lock(&cmd->t_state_lock); | ||||||
| 	cmd->transport_state &= ~CMD_T_SENT; | 	cmd->transport_state &= ~CMD_T_SENT; | ||||||
| 	spin_unlock_irq(&cmd->t_state_lock); | 	spin_unlock(&cmd->t_state_lock); | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&dev->delayed_cmd_lock); |  | ||||||
| 	list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); | 	list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); | ||||||
| 	spin_unlock(&dev->delayed_cmd_lock); | 	spin_unlock_irqrestore(&dev->delayed_cmd_lock, flags); | ||||||
| 
 | 
 | ||||||
| 	pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to delayed CMD listn", | 	pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to delayed CMD listn", | ||||||
| 		cmd->t_task_cdb[0], cmd->sam_task_attr); | 		cmd->t_task_cdb[0], cmd->sam_task_attr); | ||||||
|  | @ -2313,41 +2311,52 @@ void target_do_delayed_work(struct work_struct *work) | ||||||
| 	while (!dev->ordered_sync_in_progress) { | 	while (!dev->ordered_sync_in_progress) { | ||||||
| 		struct se_cmd *cmd; | 		struct se_cmd *cmd; | ||||||
| 
 | 
 | ||||||
| 		if (list_empty(&dev->delayed_cmd_list)) | 		/*
 | ||||||
|  | 		 * We can be woken up early/late due to races or the | ||||||
|  | 		 * extra wake up we do when adding commands to the list. | ||||||
|  | 		 * We check for both cases here. | ||||||
|  | 		 */ | ||||||
|  | 		if (list_empty(&dev->delayed_cmd_list) || | ||||||
|  | 		    !percpu_ref_is_zero(&dev->non_ordered)) | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		cmd = list_entry(dev->delayed_cmd_list.next, | 		cmd = list_entry(dev->delayed_cmd_list.next, | ||||||
| 				 struct se_cmd, se_delayed_node); | 				 struct se_cmd, se_delayed_node); | ||||||
| 
 | 		cmd->se_cmd_flags |= SCF_TASK_ORDERED_SYNC; | ||||||
| 		if (cmd->sam_task_attr == TCM_ORDERED_TAG) { |  | ||||||
| 			/*
 |  | ||||||
| 			 * Check if we started with: |  | ||||||
| 			 * [ordered] [simple] [ordered] |  | ||||||
| 			 * and we are now at the last ordered so we have to wait |  | ||||||
| 			 * for the simple cmd. |  | ||||||
| 			 */ |  | ||||||
| 			if (atomic_read(&dev->non_ordered) > 0) |  | ||||||
| 				break; |  | ||||||
| 
 |  | ||||||
| 			dev->ordered_sync_in_progress = true; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		list_del(&cmd->se_delayed_node); |  | ||||||
| 		atomic_dec_mb(&dev->delayed_cmd_count); |  | ||||||
| 		spin_unlock(&dev->delayed_cmd_lock); |  | ||||||
| 
 |  | ||||||
| 		if (cmd->sam_task_attr != TCM_ORDERED_TAG) |  | ||||||
| 			atomic_inc_mb(&dev->non_ordered); |  | ||||||
| 
 |  | ||||||
| 		cmd->transport_state |= CMD_T_SENT; | 		cmd->transport_state |= CMD_T_SENT; | ||||||
| 
 | 
 | ||||||
| 		__target_execute_cmd(cmd, true); | 		dev->ordered_sync_in_progress = true; | ||||||
| 
 | 
 | ||||||
|  | 		list_del(&cmd->se_delayed_node); | ||||||
|  | 		spin_unlock(&dev->delayed_cmd_lock); | ||||||
|  | 
 | ||||||
|  | 		__target_execute_cmd(cmd, true); | ||||||
| 		spin_lock(&dev->delayed_cmd_lock); | 		spin_lock(&dev->delayed_cmd_lock); | ||||||
| 	} | 	} | ||||||
| 	spin_unlock(&dev->delayed_cmd_lock); | 	spin_unlock(&dev->delayed_cmd_lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void transport_complete_ordered_sync(struct se_cmd *cmd) | ||||||
|  | { | ||||||
|  | 	struct se_device *dev = cmd->se_dev; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&dev->delayed_cmd_lock, flags); | ||||||
|  | 	dev->dev_cur_ordered_id++; | ||||||
|  | 
 | ||||||
|  | 	pr_debug("Incremented dev_cur_ordered_id: %u for type %d\n", | ||||||
|  | 		 dev->dev_cur_ordered_id, cmd->sam_task_attr); | ||||||
|  | 
 | ||||||
|  | 	dev->ordered_sync_in_progress = false; | ||||||
|  | 
 | ||||||
|  | 	if (list_empty(&dev->delayed_cmd_list)) | ||||||
|  | 		percpu_ref_resurrect(&dev->non_ordered); | ||||||
|  | 	else | ||||||
|  | 		schedule_work(&dev->delayed_cmd_work); | ||||||
|  | 
 | ||||||
|  | 	spin_unlock_irqrestore(&dev->delayed_cmd_lock, flags); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Called from I/O completion to determine which dormant/delayed |  * Called from I/O completion to determine which dormant/delayed | ||||||
|  * and ordered cmds need to have their tasks added to the execution queue. |  * and ordered cmds need to have their tasks added to the execution queue. | ||||||
|  | @ -2360,30 +2369,24 @@ static void transport_complete_task_attr(struct se_cmd *cmd) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (!(cmd->se_cmd_flags & SCF_TASK_ATTR_SET)) | 	if (!(cmd->se_cmd_flags & SCF_TASK_ATTR_SET)) | ||||||
| 		goto restart; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (cmd->sam_task_attr == TCM_SIMPLE_TAG) { |  | ||||||
| 		atomic_dec_mb(&dev->non_ordered); |  | ||||||
| 		dev->dev_cur_ordered_id++; |  | ||||||
| 	} else if (cmd->sam_task_attr == TCM_HEAD_TAG) { |  | ||||||
| 		atomic_dec_mb(&dev->non_ordered); |  | ||||||
| 		dev->dev_cur_ordered_id++; |  | ||||||
| 		pr_debug("Incremented dev_cur_ordered_id: %u for HEAD_OF_QUEUE\n", |  | ||||||
| 			 dev->dev_cur_ordered_id); |  | ||||||
| 	} else if (cmd->sam_task_attr == TCM_ORDERED_TAG) { |  | ||||||
| 		spin_lock(&dev->delayed_cmd_lock); |  | ||||||
| 		dev->ordered_sync_in_progress = false; |  | ||||||
| 		spin_unlock(&dev->delayed_cmd_lock); |  | ||||||
| 
 |  | ||||||
| 		dev->dev_cur_ordered_id++; |  | ||||||
| 		pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n", |  | ||||||
| 			 dev->dev_cur_ordered_id); |  | ||||||
| 	} |  | ||||||
| 	cmd->se_cmd_flags &= ~SCF_TASK_ATTR_SET; | 	cmd->se_cmd_flags &= ~SCF_TASK_ATTR_SET; | ||||||
| 
 | 
 | ||||||
| restart: | 	if (cmd->se_cmd_flags & SCF_TASK_ORDERED_SYNC) { | ||||||
| 	if (atomic_read(&dev->delayed_cmd_count) > 0) | 		transport_complete_ordered_sync(cmd); | ||||||
| 		schedule_work(&dev->delayed_cmd_work); | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	switch (cmd->sam_task_attr) { | ||||||
|  | 	case TCM_SIMPLE_TAG: | ||||||
|  | 		percpu_ref_put(&dev->non_ordered); | ||||||
|  | 		break; | ||||||
|  | 	case TCM_ORDERED_TAG: | ||||||
|  | 		/* All ordered should have been executed as sync */ | ||||||
|  | 		WARN_ON(1); | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void transport_complete_qf(struct se_cmd *cmd) | static void transport_complete_qf(struct se_cmd *cmd) | ||||||
|  |  | ||||||
|  | @ -674,7 +674,6 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) | ||||||
| 	int tag = scsi_cmd_to_rq(cmd)->tag; | 	int tag = scsi_cmd_to_rq(cmd)->tag; | ||||||
| 	struct ufshcd_lrb *lrbp = &hba->lrb[tag]; | 	struct ufshcd_lrb *lrbp = &hba->lrb[tag]; | ||||||
| 	struct ufs_hw_queue *hwq; | 	struct ufs_hw_queue *hwq; | ||||||
| 	unsigned long flags; |  | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	/* Skip task abort in case previous aborts failed and report failure */ | 	/* Skip task abort in case previous aborts failed and report failure */ | ||||||
|  | @ -713,10 +712,5 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) | ||||||
| 		return FAILED; | 		return FAILED; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&hwq->cq_lock, flags); |  | ||||||
| 	if (ufshcd_cmd_inflight(lrbp->cmd)) |  | ||||||
| 		ufshcd_release_scsi_cmd(hba, lrbp); |  | ||||||
| 	spin_unlock_irqrestore(&hwq->cq_lock, flags); |  | ||||||
| 
 |  | ||||||
| 	return SUCCESS; | 	return SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -57,6 +57,36 @@ static const char *ufs_hs_gear_to_string(enum ufs_hs_gear_tag gear) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static const char *ufs_wb_resize_hint_to_string(enum wb_resize_hint hint) | ||||||
|  | { | ||||||
|  | 	switch (hint) { | ||||||
|  | 	case WB_RESIZE_HINT_KEEP: | ||||||
|  | 		return "keep"; | ||||||
|  | 	case WB_RESIZE_HINT_DECREASE: | ||||||
|  | 		return "decrease"; | ||||||
|  | 	case WB_RESIZE_HINT_INCREASE: | ||||||
|  | 		return "increase"; | ||||||
|  | 	default: | ||||||
|  | 		return "unknown"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const char *ufs_wb_resize_status_to_string(enum wb_resize_status status) | ||||||
|  | { | ||||||
|  | 	switch (status) { | ||||||
|  | 	case WB_RESIZE_STATUS_IDLE: | ||||||
|  | 		return "idle"; | ||||||
|  | 	case WB_RESIZE_STATUS_IN_PROGRESS: | ||||||
|  | 		return "in_progress"; | ||||||
|  | 	case WB_RESIZE_STATUS_COMPLETE_SUCCESS: | ||||||
|  | 		return "complete_success"; | ||||||
|  | 	case WB_RESIZE_STATUS_GENERAL_FAILURE: | ||||||
|  | 		return "general_failure"; | ||||||
|  | 	default: | ||||||
|  | 		return "unknown"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static const char *ufshcd_uic_link_state_to_string( | static const char *ufshcd_uic_link_state_to_string( | ||||||
| 			enum uic_link_state state) | 			enum uic_link_state state) | ||||||
| { | { | ||||||
|  | @ -411,6 +441,44 @@ static ssize_t wb_flush_threshold_store(struct device *dev, | ||||||
| 	return count; | 	return count; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static const char * const wb_resize_en_mode[] = { | ||||||
|  | 	[WB_RESIZE_EN_IDLE]	= "idle", | ||||||
|  | 	[WB_RESIZE_EN_DECREASE]	= "decrease", | ||||||
|  | 	[WB_RESIZE_EN_INCREASE]	= "increase", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static ssize_t wb_resize_enable_store(struct device *dev, | ||||||
|  | 				struct device_attribute *attr, | ||||||
|  | 				const char *buf, size_t count) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = dev_get_drvdata(dev); | ||||||
|  | 	int mode; | ||||||
|  | 	ssize_t res; | ||||||
|  | 
 | ||||||
|  | 	if (!ufshcd_is_wb_allowed(hba) || !hba->dev_info.wb_enabled | ||||||
|  | 		|| !hba->dev_info.b_presrv_uspc_en | ||||||
|  | 		|| !(hba->dev_info.ext_wb_sup & UFS_DEV_WB_BUF_RESIZE)) | ||||||
|  | 		return -EOPNOTSUPP; | ||||||
|  | 
 | ||||||
|  | 	mode = sysfs_match_string(wb_resize_en_mode, buf); | ||||||
|  | 	if (mode < 0) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	down(&hba->host_sem); | ||||||
|  | 	if (!ufshcd_is_user_access_allowed(hba)) { | ||||||
|  | 		res = -EBUSY; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ufshcd_rpm_get_sync(hba); | ||||||
|  | 	res = ufshcd_wb_set_resize_en(hba, mode); | ||||||
|  | 	ufshcd_rpm_put_sync(hba); | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	up(&hba->host_sem); | ||||||
|  | 	return res < 0 ? res : count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * pm_qos_enable_show - sysfs handler to show pm qos enable value |  * pm_qos_enable_show - sysfs handler to show pm qos enable value | ||||||
|  * @dev: device associated with the UFS controller |  * @dev: device associated with the UFS controller | ||||||
|  | @ -526,6 +594,7 @@ static DEVICE_ATTR_RW(auto_hibern8); | ||||||
| static DEVICE_ATTR_RW(wb_on); | static DEVICE_ATTR_RW(wb_on); | ||||||
| static DEVICE_ATTR_RW(enable_wb_buf_flush); | static DEVICE_ATTR_RW(enable_wb_buf_flush); | ||||||
| static DEVICE_ATTR_RW(wb_flush_threshold); | static DEVICE_ATTR_RW(wb_flush_threshold); | ||||||
|  | static DEVICE_ATTR_WO(wb_resize_enable); | ||||||
| static DEVICE_ATTR_RW(rtc_update_ms); | static DEVICE_ATTR_RW(rtc_update_ms); | ||||||
| static DEVICE_ATTR_RW(pm_qos_enable); | static DEVICE_ATTR_RW(pm_qos_enable); | ||||||
| static DEVICE_ATTR_RO(critical_health); | static DEVICE_ATTR_RO(critical_health); | ||||||
|  | @ -543,6 +612,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = { | ||||||
| 	&dev_attr_wb_on.attr, | 	&dev_attr_wb_on.attr, | ||||||
| 	&dev_attr_enable_wb_buf_flush.attr, | 	&dev_attr_enable_wb_buf_flush.attr, | ||||||
| 	&dev_attr_wb_flush_threshold.attr, | 	&dev_attr_wb_flush_threshold.attr, | ||||||
|  | 	&dev_attr_wb_resize_enable.attr, | ||||||
| 	&dev_attr_rtc_update_ms.attr, | 	&dev_attr_rtc_update_ms.attr, | ||||||
| 	&dev_attr_pm_qos_enable.attr, | 	&dev_attr_pm_qos_enable.attr, | ||||||
| 	&dev_attr_critical_health.attr, | 	&dev_attr_critical_health.attr, | ||||||
|  | @ -1549,6 +1619,67 @@ static inline bool ufshcd_is_wb_attrs(enum attr_idn idn) | ||||||
| 		idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE; | 		idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int wb_read_resize_attrs(struct ufs_hba *hba, | ||||||
|  | 			enum attr_idn idn, u32 *attr_val) | ||||||
|  | { | ||||||
|  | 	u8 index = 0; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (!ufshcd_is_wb_allowed(hba) || !hba->dev_info.wb_enabled | ||||||
|  | 		|| !hba->dev_info.b_presrv_uspc_en | ||||||
|  | 		|| !(hba->dev_info.ext_wb_sup & UFS_DEV_WB_BUF_RESIZE)) | ||||||
|  | 		return -EOPNOTSUPP; | ||||||
|  | 
 | ||||||
|  | 	down(&hba->host_sem); | ||||||
|  | 	if (!ufshcd_is_user_access_allowed(hba)) { | ||||||
|  | 		up(&hba->host_sem); | ||||||
|  | 		return -EBUSY; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	index = ufshcd_wb_get_query_index(hba); | ||||||
|  | 	ufshcd_rpm_get_sync(hba); | ||||||
|  | 	ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, | ||||||
|  | 			idn, index, 0, attr_val); | ||||||
|  | 	ufshcd_rpm_put_sync(hba); | ||||||
|  | 
 | ||||||
|  | 	up(&hba->host_sem); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t wb_resize_hint_show(struct device *dev, | ||||||
|  | 				struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = dev_get_drvdata(dev); | ||||||
|  | 	int ret; | ||||||
|  | 	u32 value; | ||||||
|  | 
 | ||||||
|  | 	ret = wb_read_resize_attrs(hba, | ||||||
|  | 			QUERY_ATTR_IDN_WB_BUF_RESIZE_HINT, &value); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	return sysfs_emit(buf, "%s\n", ufs_wb_resize_hint_to_string(value)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DEVICE_ATTR_RO(wb_resize_hint); | ||||||
|  | 
 | ||||||
|  | static ssize_t wb_resize_status_show(struct device *dev, | ||||||
|  | 				struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = dev_get_drvdata(dev); | ||||||
|  | 	int ret; | ||||||
|  | 	u32 value; | ||||||
|  | 
 | ||||||
|  | 	ret = wb_read_resize_attrs(hba, | ||||||
|  | 			QUERY_ATTR_IDN_WB_BUF_RESIZE_STATUS, &value); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	return sysfs_emit(buf, "%s\n", ufs_wb_resize_status_to_string(value)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DEVICE_ATTR_RO(wb_resize_status); | ||||||
|  | 
 | ||||||
| #define UFS_ATTRIBUTE(_name, _uname)					\ | #define UFS_ATTRIBUTE(_name, _uname)					\ | ||||||
| static ssize_t _name##_show(struct device *dev,				\ | static ssize_t _name##_show(struct device *dev,				\ | ||||||
| 	struct device_attribute *attr, char *buf)			\ | 	struct device_attribute *attr, char *buf)			\ | ||||||
|  | @ -1622,6 +1753,8 @@ static struct attribute *ufs_sysfs_attributes[] = { | ||||||
| 	&dev_attr_wb_avail_buf.attr, | 	&dev_attr_wb_avail_buf.attr, | ||||||
| 	&dev_attr_wb_life_time_est.attr, | 	&dev_attr_wb_life_time_est.attr, | ||||||
| 	&dev_attr_wb_cur_buf.attr, | 	&dev_attr_wb_cur_buf.attr, | ||||||
|  | 	&dev_attr_wb_resize_hint.attr, | ||||||
|  | 	&dev_attr_wb_resize_status.attr, | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -53,7 +53,7 @@ | ||||||
| /* UIC command timeout, unit: ms */ | /* UIC command timeout, unit: ms */ | ||||||
| enum { | enum { | ||||||
| 	UIC_CMD_TIMEOUT_DEFAULT	= 500, | 	UIC_CMD_TIMEOUT_DEFAULT	= 500, | ||||||
| 	UIC_CMD_TIMEOUT_MAX	= 2000, | 	UIC_CMD_TIMEOUT_MAX	= 5000, | ||||||
| }; | }; | ||||||
| /* NOP OUT retries waiting for NOP IN response */ | /* NOP OUT retries waiting for NOP IN response */ | ||||||
| #define NOP_OUT_RETRIES    10 | #define NOP_OUT_RETRIES    10 | ||||||
|  | @ -63,7 +63,11 @@ enum { | ||||||
| /* Query request retries */ | /* Query request retries */ | ||||||
| #define QUERY_REQ_RETRIES 3 | #define QUERY_REQ_RETRIES 3 | ||||||
| /* Query request timeout */ | /* Query request timeout */ | ||||||
| #define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ | enum { | ||||||
|  | 	QUERY_REQ_TIMEOUT_MIN     = 1, | ||||||
|  | 	QUERY_REQ_TIMEOUT_DEFAULT = 1500, | ||||||
|  | 	QUERY_REQ_TIMEOUT_MAX     = 30000 | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| /* Advanced RPMB request timeout */ | /* Advanced RPMB request timeout */ | ||||||
| #define ADVANCED_RPMB_REQ_TIMEOUT  3000 /* 3 seconds */ | #define ADVANCED_RPMB_REQ_TIMEOUT  3000 /* 3 seconds */ | ||||||
|  | @ -133,7 +137,24 @@ static const struct kernel_param_ops uic_cmd_timeout_ops = { | ||||||
| 
 | 
 | ||||||
| module_param_cb(uic_cmd_timeout, &uic_cmd_timeout_ops, &uic_cmd_timeout, 0644); | module_param_cb(uic_cmd_timeout, &uic_cmd_timeout_ops, &uic_cmd_timeout, 0644); | ||||||
| MODULE_PARM_DESC(uic_cmd_timeout, | MODULE_PARM_DESC(uic_cmd_timeout, | ||||||
| 		 "UFS UIC command timeout in milliseconds. Defaults to 500ms. Supported values range from 500ms to 2 seconds inclusively"); | 		 "UFS UIC command timeout in milliseconds. Defaults to 500ms. Supported values range from 500ms to 5 seconds inclusively"); | ||||||
|  | 
 | ||||||
|  | static unsigned int dev_cmd_timeout = QUERY_REQ_TIMEOUT_DEFAULT; | ||||||
|  | 
 | ||||||
|  | static int dev_cmd_timeout_set(const char *val, const struct kernel_param *kp) | ||||||
|  | { | ||||||
|  | 	return param_set_uint_minmax(val, kp, QUERY_REQ_TIMEOUT_MIN, | ||||||
|  | 				     QUERY_REQ_TIMEOUT_MAX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct kernel_param_ops dev_cmd_timeout_ops = { | ||||||
|  | 	.set = dev_cmd_timeout_set, | ||||||
|  | 	.get = param_get_uint, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | module_param_cb(dev_cmd_timeout, &dev_cmd_timeout_ops, &dev_cmd_timeout, 0644); | ||||||
|  | MODULE_PARM_DESC(dev_cmd_timeout, | ||||||
|  | 		 "UFS Device command timeout in milliseconds. Defaults to 1.5s. Supported values range from 1ms to 30 seconds inclusively"); | ||||||
| 
 | 
 | ||||||
| #define ufshcd_toggle_vreg(_dev, _vreg, _on)				\ | #define ufshcd_toggle_vreg(_dev, _vreg, _on)				\ | ||||||
| 	({                                                              \ | 	({                                                              \ | ||||||
|  | @ -432,7 +453,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, | ||||||
| 	u8 opcode = 0, group_id = 0; | 	u8 opcode = 0, group_id = 0; | ||||||
| 	u32 doorbell = 0; | 	u32 doorbell = 0; | ||||||
| 	u32 intr; | 	u32 intr; | ||||||
| 	int hwq_id = -1; | 	u32 hwq_id = 0; | ||||||
| 	struct ufshcd_lrb *lrbp = &hba->lrb[tag]; | 	struct ufshcd_lrb *lrbp = &hba->lrb[tag]; | ||||||
| 	struct scsi_cmnd *cmd = lrbp->cmd; | 	struct scsi_cmnd *cmd = lrbp->cmd; | ||||||
| 	struct request *rq = scsi_cmd_to_rq(cmd); | 	struct request *rq = scsi_cmd_to_rq(cmd); | ||||||
|  | @ -644,9 +665,6 @@ static void ufshcd_print_host_state(struct ufs_hba *hba) | ||||||
| 		"last_hibern8_exit_tstamp at %lld us, hibern8_exit_cnt=%d\n", | 		"last_hibern8_exit_tstamp at %lld us, hibern8_exit_cnt=%d\n", | ||||||
| 		div_u64(hba->ufs_stats.last_hibern8_exit_tstamp, 1000), | 		div_u64(hba->ufs_stats.last_hibern8_exit_tstamp, 1000), | ||||||
| 		hba->ufs_stats.hibern8_exit_cnt); | 		hba->ufs_stats.hibern8_exit_cnt); | ||||||
| 	dev_err(hba->dev, "last intr at %lld us, last intr status=0x%x\n", |  | ||||||
| 		div_u64(hba->ufs_stats.last_intr_ts, 1000), |  | ||||||
| 		hba->ufs_stats.last_intr_status); |  | ||||||
| 	dev_err(hba->dev, "error handling flags=0x%x, req. abort count=%d\n", | 	dev_err(hba->dev, "error handling flags=0x%x, req. abort count=%d\n", | ||||||
| 		hba->eh_flags, hba->req_abort_count); | 		hba->eh_flags, hba->req_abort_count); | ||||||
| 	dev_err(hba->dev, "hba->ufs_version=0x%x, Host capabilities=0x%x, caps=0x%x\n", | 	dev_err(hba->dev, "hba->ufs_version=0x%x, Host capabilities=0x%x, caps=0x%x\n", | ||||||
|  | @ -3365,7 +3383,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, | ||||||
| 	struct ufs_query_req *request = NULL; | 	struct ufs_query_req *request = NULL; | ||||||
| 	struct ufs_query_res *response = NULL; | 	struct ufs_query_res *response = NULL; | ||||||
| 	int err, selector = 0; | 	int err, selector = 0; | ||||||
| 	int timeout = QUERY_REQ_TIMEOUT; | 	int timeout = dev_cmd_timeout; | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(!hba); | 	BUG_ON(!hba); | ||||||
| 
 | 
 | ||||||
|  | @ -3462,7 +3480,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, | ||||||
| 		goto out_unlock; | 		goto out_unlock; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); | 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout); | ||||||
| 
 | 
 | ||||||
| 	if (err) { | 	if (err) { | ||||||
| 		dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", | 		dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", | ||||||
|  | @ -3558,7 +3576,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, | ||||||
| 		goto out_unlock; | 		goto out_unlock; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); | 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout); | ||||||
| 
 | 
 | ||||||
| 	if (err) { | 	if (err) { | ||||||
| 		dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", | 		dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", | ||||||
|  | @ -6020,7 +6038,7 @@ int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id) | ||||||
| 
 | 
 | ||||||
| 	request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; | 	request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; | ||||||
| 
 | 
 | ||||||
| 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); | 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout); | ||||||
| 
 | 
 | ||||||
| 	if (err) { | 	if (err) { | ||||||
| 		dev_err(hba->dev, "%s: failed to read device level exception %d\n", | 		dev_err(hba->dev, "%s: failed to read device level exception %d\n", | ||||||
|  | @ -6107,6 +6125,21 @@ int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int ufshcd_wb_set_resize_en(struct ufs_hba *hba, enum wb_resize_en en_mode) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 	u8 index; | ||||||
|  | 
 | ||||||
|  | 	index = ufshcd_wb_get_query_index(hba); | ||||||
|  | 	ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, | ||||||
|  | 				QUERY_ATTR_IDN_WB_BUF_RESIZE_EN, index, 0, &en_mode); | ||||||
|  | 	if (ret) | ||||||
|  | 		dev_err(hba->dev, "%s: Enable WB buf resize operation failed %d\n", | ||||||
|  | 			__func__, ret); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static bool ufshcd_wb_curr_buff_threshold_check(struct ufs_hba *hba, | static bool ufshcd_wb_curr_buff_threshold_check(struct ufs_hba *hba, | ||||||
| 						u32 avail_buf) | 						u32 avail_buf) | ||||||
| { | { | ||||||
|  | @ -6572,7 +6605,7 @@ static void ufshcd_err_handler(struct work_struct *work) | ||||||
| 	hba = container_of(work, struct ufs_hba, eh_work); | 	hba = container_of(work, struct ufs_hba, eh_work); | ||||||
| 
 | 
 | ||||||
| 	dev_info(hba->dev, | 	dev_info(hba->dev, | ||||||
| 		 "%s started; HBA state %s; powered %d; shutting down %d; saved_err = %d; saved_uic_err = %d; force_reset = %d%s\n", | 		 "%s started; HBA state %s; powered %d; shutting down %d; saved_err = 0x%x; saved_uic_err = 0x%x; force_reset = %d%s\n", | ||||||
| 		 __func__, ufshcd_state_name[hba->ufshcd_state], | 		 __func__, ufshcd_state_name[hba->ufshcd_state], | ||||||
| 		 hba->is_powered, hba->shutting_down, hba->saved_err, | 		 hba->is_powered, hba->shutting_down, hba->saved_err, | ||||||
| 		 hba->saved_uic_err, hba->force_reset, | 		 hba->saved_uic_err, hba->force_reset, | ||||||
|  | @ -7001,7 +7034,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ufshcd_intr - Main interrupt service routine |  * ufshcd_threaded_intr - Threaded interrupt service routine | ||||||
|  * @irq: irq number |  * @irq: irq number | ||||||
|  * @__hba: pointer to adapter instance |  * @__hba: pointer to adapter instance | ||||||
|  * |  * | ||||||
|  | @ -7009,16 +7042,14 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) | ||||||
|  *  IRQ_HANDLED - If interrupt is valid |  *  IRQ_HANDLED - If interrupt is valid | ||||||
|  *  IRQ_NONE    - If invalid interrupt |  *  IRQ_NONE    - If invalid interrupt | ||||||
|  */ |  */ | ||||||
| static irqreturn_t ufshcd_intr(int irq, void *__hba) | static irqreturn_t ufshcd_threaded_intr(int irq, void *__hba) | ||||||
| { | { | ||||||
| 	u32 intr_status, enabled_intr_status = 0; | 	u32 last_intr_status, intr_status, enabled_intr_status = 0; | ||||||
| 	irqreturn_t retval = IRQ_NONE; | 	irqreturn_t retval = IRQ_NONE; | ||||||
| 	struct ufs_hba *hba = __hba; | 	struct ufs_hba *hba = __hba; | ||||||
| 	int retries = hba->nutrs; | 	int retries = hba->nutrs; | ||||||
| 
 | 
 | ||||||
| 	intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); | 	last_intr_status = intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); | ||||||
| 	hba->ufs_stats.last_intr_status = intr_status; |  | ||||||
| 	hba->ufs_stats.last_intr_ts = local_clock(); |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * There could be max of hba->nutrs reqs in flight and in worst case | 	 * There could be max of hba->nutrs reqs in flight and in worst case | ||||||
|  | @ -7042,7 +7073,7 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba) | ||||||
| 		dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x (0x%08x, 0x%08x)\n", | 		dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x (0x%08x, 0x%08x)\n", | ||||||
| 					__func__, | 					__func__, | ||||||
| 					intr_status, | 					intr_status, | ||||||
| 					hba->ufs_stats.last_intr_status, | 					last_intr_status, | ||||||
| 					enabled_intr_status); | 					enabled_intr_status); | ||||||
| 		ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: "); | 		ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: "); | ||||||
| 	} | 	} | ||||||
|  | @ -7050,6 +7081,29 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba) | ||||||
| 	return retval; | 	return retval; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * ufshcd_intr - Main interrupt service routine | ||||||
|  |  * @irq: irq number | ||||||
|  |  * @__hba: pointer to adapter instance | ||||||
|  |  * | ||||||
|  |  * Return: | ||||||
|  |  *  IRQ_HANDLED     - If interrupt is valid | ||||||
|  |  *  IRQ_WAKE_THREAD - If handling is moved to threaded handled | ||||||
|  |  *  IRQ_NONE        - If invalid interrupt | ||||||
|  |  */ | ||||||
|  | static irqreturn_t ufshcd_intr(int irq, void *__hba) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = __hba; | ||||||
|  | 
 | ||||||
|  | 	/* Move interrupt handling to thread when MCQ & ESI are not enabled */ | ||||||
|  | 	if (!hba->mcq_enabled || !hba->mcq_esi_enabled) | ||||||
|  | 		return IRQ_WAKE_THREAD; | ||||||
|  | 
 | ||||||
|  | 	/* Directly handle interrupts since MCQ ESI handlers does the hard job */ | ||||||
|  | 	return ufshcd_sl_intr(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS) & | ||||||
|  | 				   ufshcd_readl(hba, REG_INTERRUPT_ENABLE)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag) | static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag) | ||||||
| { | { | ||||||
| 	int err = 0; | 	int err = 0; | ||||||
|  | @ -7245,7 +7299,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, | ||||||
| 	 * bound to fail since dev_cmd.query and dev_cmd.type were left empty. | 	 * bound to fail since dev_cmd.query and dev_cmd.type were left empty. | ||||||
| 	 * read the response directly ignoring all errors. | 	 * read the response directly ignoring all errors. | ||||||
| 	 */ | 	 */ | ||||||
| 	ufshcd_issue_dev_cmd(hba, lrbp, tag, QUERY_REQ_TIMEOUT); | 	ufshcd_issue_dev_cmd(hba, lrbp, tag, dev_cmd_timeout); | ||||||
| 
 | 
 | ||||||
| 	/* just copy the upiu response as it is */ | 	/* just copy the upiu response as it is */ | ||||||
| 	memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); | 	memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); | ||||||
|  | @ -8107,6 +8161,9 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, const u8 *desc_buf) | ||||||
| 	 */ | 	 */ | ||||||
| 	dev_info->wb_buffer_type = desc_buf[DEVICE_DESC_PARAM_WB_TYPE]; | 	dev_info->wb_buffer_type = desc_buf[DEVICE_DESC_PARAM_WB_TYPE]; | ||||||
| 
 | 
 | ||||||
|  | 	dev_info->ext_wb_sup =  get_unaligned_be16(desc_buf + | ||||||
|  | 						DEVICE_DESC_PARAM_EXT_WB_SUP); | ||||||
|  | 
 | ||||||
| 	dev_info->b_presrv_uspc_en = | 	dev_info->b_presrv_uspc_en = | ||||||
| 		desc_buf[DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN]; | 		desc_buf[DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN]; | ||||||
| 
 | 
 | ||||||
|  | @ -8678,7 +8735,7 @@ static void ufshcd_set_timestamp_attr(struct ufs_hba *hba) | ||||||
| 
 | 
 | ||||||
| 	put_unaligned_be64(ktime_get_real_ns(), &upiu_data->osf3); | 	put_unaligned_be64(ktime_get_real_ns(), &upiu_data->osf3); | ||||||
| 
 | 
 | ||||||
| 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); | 	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout); | ||||||
| 
 | 
 | ||||||
| 	if (err) | 	if (err) | ||||||
| 		dev_err(hba->dev, "%s: failed to set timestamp %d\n", | 		dev_err(hba->dev, "%s: failed to set timestamp %d\n", | ||||||
|  | @ -8793,6 +8850,7 @@ static void ufshcd_config_mcq(struct ufs_hba *hba) | ||||||
| 	u32 intrs; | 	u32 intrs; | ||||||
| 
 | 
 | ||||||
| 	ret = ufshcd_mcq_vops_config_esi(hba); | 	ret = ufshcd_mcq_vops_config_esi(hba); | ||||||
|  | 	hba->mcq_esi_enabled = !ret; | ||||||
| 	dev_info(hba->dev, "ESI %sconfigured\n", ret ? "is not " : ""); | 	dev_info(hba->dev, "ESI %sconfigured\n", ret ? "is not " : ""); | ||||||
| 
 | 
 | ||||||
| 	intrs = UFSHCD_ENABLE_MCQ_INTRS; | 	intrs = UFSHCD_ENABLE_MCQ_INTRS; | ||||||
|  | @ -10654,7 +10712,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) | ||||||
| 	ufshcd_readl(hba, REG_INTERRUPT_ENABLE); | 	ufshcd_readl(hba, REG_INTERRUPT_ENABLE); | ||||||
| 
 | 
 | ||||||
| 	/* IRQ registration */ | 	/* IRQ registration */ | ||||||
| 	err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba); | 	err = devm_request_threaded_irq(dev, irq, ufshcd_intr, ufshcd_threaded_intr, | ||||||
|  | 					IRQF_ONESHOT | IRQF_SHARED, UFSHCD, hba); | ||||||
| 	if (err) { | 	if (err) { | ||||||
| 		dev_err(hba->dev, "request irq failed\n"); | 		dev_err(hba->dev, "request irq failed\n"); | ||||||
| 		goto out_disable; | 		goto out_disable; | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/acpi.h> | #include <linux/acpi.h> | ||||||
| #include <linux/clk.h> | #include <linux/clk.h> | ||||||
|  | #include <linux/cleanup.h> | ||||||
| #include <linux/delay.h> | #include <linux/delay.h> | ||||||
| #include <linux/devfreq.h> | #include <linux/devfreq.h> | ||||||
| #include <linux/gpio/consumer.h> | #include <linux/gpio/consumer.h> | ||||||
|  | @ -102,6 +103,24 @@ static const struct __ufs_qcom_bw_table { | ||||||
| 	[MODE_MAX][0][0]		    = { 7643136,	819200 }, | 	[MODE_MAX][0][0]		    = { 7643136,	819200 }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static const struct { | ||||||
|  | 	int nminor; | ||||||
|  | 	char *prefix; | ||||||
|  | } testbus_info[TSTBUS_MAX] = { | ||||||
|  | 	[TSTBUS_UAWM]     = {32, "TSTBUS_UAWM"}, | ||||||
|  | 	[TSTBUS_UARM]     = {32, "TSTBUS_UARM"}, | ||||||
|  | 	[TSTBUS_TXUC]     = {32, "TSTBUS_TXUC"}, | ||||||
|  | 	[TSTBUS_RXUC]     = {32, "TSTBUS_RXUC"}, | ||||||
|  | 	[TSTBUS_DFC]      = {32, "TSTBUS_DFC"}, | ||||||
|  | 	[TSTBUS_TRLUT]    = {32, "TSTBUS_TRLUT"}, | ||||||
|  | 	[TSTBUS_TMRLUT]   = {32, "TSTBUS_TMRLUT"}, | ||||||
|  | 	[TSTBUS_OCSC]     = {32, "TSTBUS_OCSC"}, | ||||||
|  | 	[TSTBUS_UTP_HCI]  = {32, "TSTBUS_UTP_HCI"}, | ||||||
|  | 	[TSTBUS_COMBINED] = {32, "TSTBUS_COMBINED"}, | ||||||
|  | 	[TSTBUS_WRAPPER]  = {32, "TSTBUS_WRAPPER"}, | ||||||
|  | 	[TSTBUS_UNIPRO]   = {256, "TSTBUS_UNIPRO"}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); | static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); | ||||||
| static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq); | static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq); | ||||||
| 
 | 
 | ||||||
|  | @ -173,7 +192,7 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host) | ||||||
| 
 | 
 | ||||||
| 	profile->ll_ops = ufs_qcom_crypto_ops; | 	profile->ll_ops = ufs_qcom_crypto_ops; | ||||||
| 	profile->max_dun_bytes_supported = 8; | 	profile->max_dun_bytes_supported = 8; | ||||||
| 	profile->key_types_supported = BLK_CRYPTO_KEY_TYPE_RAW; | 	profile->key_types_supported = qcom_ice_get_supported_key_type(ice); | ||||||
| 	profile->dev = dev; | 	profile->dev = dev; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -221,17 +240,8 @@ static int ufs_qcom_ice_keyslot_program(struct blk_crypto_profile *profile, | ||||||
| 	struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 	struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	/* Only AES-256-XTS has been tested so far. */ |  | ||||||
| 	if (key->crypto_cfg.crypto_mode != BLK_ENCRYPTION_MODE_AES_256_XTS) |  | ||||||
| 		return -EOPNOTSUPP; |  | ||||||
| 
 |  | ||||||
| 	ufshcd_hold(hba); | 	ufshcd_hold(hba); | ||||||
| 	err = qcom_ice_program_key(host->ice, | 	err = qcom_ice_program_key(host->ice, slot, key); | ||||||
| 				   QCOM_ICE_CRYPTO_ALG_AES_XTS, |  | ||||||
| 				   QCOM_ICE_CRYPTO_KEY_SIZE_256, |  | ||||||
| 				   key->bytes, |  | ||||||
| 				   key->crypto_cfg.data_unit_size / 512, |  | ||||||
| 				   slot); |  | ||||||
| 	ufshcd_release(hba); | 	ufshcd_release(hba); | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
|  | @ -250,9 +260,53 @@ static int ufs_qcom_ice_keyslot_evict(struct blk_crypto_profile *profile, | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int ufs_qcom_ice_derive_sw_secret(struct blk_crypto_profile *profile, | ||||||
|  | 					 const u8 *eph_key, size_t eph_key_size, | ||||||
|  | 					 u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = ufs_hba_from_crypto_profile(profile); | ||||||
|  | 	struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||||||
|  | 
 | ||||||
|  | 	return qcom_ice_derive_sw_secret(host->ice, eph_key, eph_key_size, | ||||||
|  | 					 sw_secret); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ufs_qcom_ice_import_key(struct blk_crypto_profile *profile, | ||||||
|  | 				   const u8 *raw_key, size_t raw_key_size, | ||||||
|  | 				   u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = ufs_hba_from_crypto_profile(profile); | ||||||
|  | 	struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||||||
|  | 
 | ||||||
|  | 	return qcom_ice_import_key(host->ice, raw_key, raw_key_size, lt_key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ufs_qcom_ice_generate_key(struct blk_crypto_profile *profile, | ||||||
|  | 				     u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = ufs_hba_from_crypto_profile(profile); | ||||||
|  | 	struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||||||
|  | 
 | ||||||
|  | 	return qcom_ice_generate_key(host->ice, lt_key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ufs_qcom_ice_prepare_key(struct blk_crypto_profile *profile, | ||||||
|  | 				    const u8 *lt_key, size_t lt_key_size, | ||||||
|  | 				    u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) | ||||||
|  | { | ||||||
|  | 	struct ufs_hba *hba = ufs_hba_from_crypto_profile(profile); | ||||||
|  | 	struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||||||
|  | 
 | ||||||
|  | 	return qcom_ice_prepare_key(host->ice, lt_key, lt_key_size, eph_key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static const struct blk_crypto_ll_ops ufs_qcom_crypto_ops = { | static const struct blk_crypto_ll_ops ufs_qcom_crypto_ops = { | ||||||
| 	.keyslot_program	= ufs_qcom_ice_keyslot_program, | 	.keyslot_program	= ufs_qcom_ice_keyslot_program, | ||||||
| 	.keyslot_evict		= ufs_qcom_ice_keyslot_evict, | 	.keyslot_evict		= ufs_qcom_ice_keyslot_evict, | ||||||
|  | 	.derive_sw_secret	= ufs_qcom_ice_derive_sw_secret, | ||||||
|  | 	.import_key		= ufs_qcom_ice_import_key, | ||||||
|  | 	.generate_key		= ufs_qcom_ice_generate_key, | ||||||
|  | 	.prepare_key		= ufs_qcom_ice_prepare_key, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #else | #else | ||||||
|  | @ -1609,6 +1663,85 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void ufs_qcom_dump_testbus(struct ufs_hba *hba) | ||||||
|  | { | ||||||
|  | 	struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||||||
|  | 	int i, j, nminor = 0, testbus_len = 0; | ||||||
|  | 	u32 *testbus __free(kfree) = NULL; | ||||||
|  | 	char *prefix; | ||||||
|  | 
 | ||||||
|  | 	testbus = kmalloc_array(256, sizeof(u32), GFP_KERNEL); | ||||||
|  | 	if (!testbus) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	for (j = 0; j < TSTBUS_MAX; j++) { | ||||||
|  | 		nminor = testbus_info[j].nminor; | ||||||
|  | 		prefix = testbus_info[j].prefix; | ||||||
|  | 		host->testbus.select_major = j; | ||||||
|  | 		testbus_len = nminor * sizeof(u32); | ||||||
|  | 		for (i = 0; i < nminor; i++) { | ||||||
|  | 			host->testbus.select_minor = i; | ||||||
|  | 			ufs_qcom_testbus_config(host); | ||||||
|  | 			testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS); | ||||||
|  | 		} | ||||||
|  | 		print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, | ||||||
|  | 			       16, 4, testbus, testbus_len, false); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, | ||||||
|  | 			      const char *prefix, enum ufshcd_res id) | ||||||
|  | { | ||||||
|  | 	u32 *regs __free(kfree) = NULL; | ||||||
|  | 	size_t pos; | ||||||
|  | 
 | ||||||
|  | 	if (offset % 4 != 0 || len % 4 != 0) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	regs = kzalloc(len, GFP_ATOMIC); | ||||||
|  | 	if (!regs) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	for (pos = 0; pos < len; pos += 4) | ||||||
|  | 		regs[pos / 4] = readl(hba->res[id].base + offset + pos); | ||||||
|  | 
 | ||||||
|  | 	print_hex_dump(KERN_ERR, prefix, | ||||||
|  | 		       len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE, | ||||||
|  | 		       16, 4, regs, len, false); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ufs_qcom_dump_mcq_hci_regs(struct ufs_hba *hba) | ||||||
|  | { | ||||||
|  | 	struct dump_info { | ||||||
|  | 		size_t offset; | ||||||
|  | 		size_t len; | ||||||
|  | 		const char *prefix; | ||||||
|  | 		enum ufshcd_res id; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct dump_info mcq_dumps[] = { | ||||||
|  | 		{0x0, 256 * 4, "MCQ HCI-0 ", RES_MCQ}, | ||||||
|  | 		{0x400, 256 * 4, "MCQ HCI-1 ", RES_MCQ}, | ||||||
|  | 		{0x0, 5 * 4, "MCQ VS-0 ", RES_MCQ_VS}, | ||||||
|  | 		{0x0, 256 * 4, "MCQ SQD-0 ", RES_MCQ_SQD}, | ||||||
|  | 		{0x400, 256 * 4, "MCQ SQD-1 ", RES_MCQ_SQD}, | ||||||
|  | 		{0x800, 256 * 4, "MCQ SQD-2 ", RES_MCQ_SQD}, | ||||||
|  | 		{0xc00, 256 * 4, "MCQ SQD-3 ", RES_MCQ_SQD}, | ||||||
|  | 		{0x1000, 256 * 4, "MCQ SQD-4 ", RES_MCQ_SQD}, | ||||||
|  | 		{0x1400, 256 * 4, "MCQ SQD-5 ", RES_MCQ_SQD}, | ||||||
|  | 		{0x1800, 256 * 4, "MCQ SQD-6 ", RES_MCQ_SQD}, | ||||||
|  | 		{0x1c00, 256 * 4, "MCQ SQD-7 ", RES_MCQ_SQD}, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	for (int i = 0; i < ARRAY_SIZE(mcq_dumps); i++) { | ||||||
|  | 		ufs_qcom_dump_regs(hba, mcq_dumps[i].offset, mcq_dumps[i].len, | ||||||
|  | 				   mcq_dumps[i].prefix, mcq_dumps[i].id); | ||||||
|  | 		cond_resched(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) | static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) | ||||||
| { | { | ||||||
| 	u32 reg; | 	u32 reg; | ||||||
|  | @ -1616,6 +1749,15 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) | ||||||
| 
 | 
 | ||||||
| 	host = ufshcd_get_variant(hba); | 	host = ufshcd_get_variant(hba); | ||||||
| 
 | 
 | ||||||
|  | 	dev_err(hba->dev, "HW_H8_ENTER_CNT=%d\n", ufshcd_readl(hba, REG_UFS_HW_H8_ENTER_CNT)); | ||||||
|  | 	dev_err(hba->dev, "HW_H8_EXIT_CNT=%d\n", ufshcd_readl(hba, REG_UFS_HW_H8_EXIT_CNT)); | ||||||
|  | 
 | ||||||
|  | 	dev_err(hba->dev, "SW_H8_ENTER_CNT=%d\n", ufshcd_readl(hba, REG_UFS_SW_H8_ENTER_CNT)); | ||||||
|  | 	dev_err(hba->dev, "SW_H8_EXIT_CNT=%d\n", ufshcd_readl(hba, REG_UFS_SW_H8_EXIT_CNT)); | ||||||
|  | 
 | ||||||
|  | 	dev_err(hba->dev, "SW_AFTER_HW_H8_ENTER_CNT=%d\n", | ||||||
|  | 			ufshcd_readl(hba, REG_UFS_SW_AFTER_HW_H8_ENTER_CNT)); | ||||||
|  | 
 | ||||||
| 	ufshcd_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16 * 4, | 	ufshcd_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16 * 4, | ||||||
| 			 "HCI Vendor Specific Registers "); | 			 "HCI Vendor Specific Registers "); | ||||||
| 
 | 
 | ||||||
|  | @ -1658,6 +1800,23 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) | ||||||
| 
 | 
 | ||||||
| 	reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT); | 	reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT); | ||||||
| 	ufshcd_dump_regs(hba, reg, 9 * 4, "UFS_DBG_RD_REG_TMRLUT "); | 	ufshcd_dump_regs(hba, reg, 9 * 4, "UFS_DBG_RD_REG_TMRLUT "); | ||||||
|  | 
 | ||||||
|  | 	if (hba->mcq_enabled) { | ||||||
|  | 		reg = ufs_qcom_get_debug_reg_offset(host, UFS_RD_REG_MCQ); | ||||||
|  | 		ufshcd_dump_regs(hba, reg, 64 * 4, "HCI MCQ Debug Registers "); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* ensure below dumps occur only in task context due to blocking calls. */ | ||||||
|  | 	if (in_task()) { | ||||||
|  | 		/* Dump MCQ Host Vendor Specific Registers */ | ||||||
|  | 		if (hba->mcq_enabled) | ||||||
|  | 			ufs_qcom_dump_mcq_hci_regs(hba); | ||||||
|  | 
 | ||||||
|  | 		/* voluntarily yield the CPU as we are dumping too much data */ | ||||||
|  | 		ufshcd_dump_regs(hba, UFS_TEST_BUS, 4, "UFS_TEST_BUS "); | ||||||
|  | 		cond_resched(); | ||||||
|  | 		ufs_qcom_dump_testbus(hba); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
|  | @ -50,6 +50,8 @@ enum { | ||||||
| 	 */ | 	 */ | ||||||
| 	UFS_AH8_CFG				= 0xFC, | 	UFS_AH8_CFG				= 0xFC, | ||||||
| 
 | 
 | ||||||
|  | 	UFS_RD_REG_MCQ				= 0xD00, | ||||||
|  | 
 | ||||||
| 	REG_UFS_MEM_ICE_CONFIG			= 0x260C, | 	REG_UFS_MEM_ICE_CONFIG			= 0x260C, | ||||||
| 	REG_UFS_MEM_ICE_NUM_CORE		= 0x2664, | 	REG_UFS_MEM_ICE_NUM_CORE		= 0x2664, | ||||||
| 
 | 
 | ||||||
|  | @ -75,6 +77,15 @@ enum { | ||||||
| 	UFS_UFS_DBG_RD_EDTL_RAM			= 0x1900, | 	UFS_UFS_DBG_RD_EDTL_RAM			= 0x1900, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* QCOM UFS HC vendor specific Hibern8 count registers */ | ||||||
|  | enum { | ||||||
|  | 	REG_UFS_HW_H8_ENTER_CNT			= 0x2700, | ||||||
|  | 	REG_UFS_SW_H8_ENTER_CNT			= 0x2704, | ||||||
|  | 	REG_UFS_SW_AFTER_HW_H8_ENTER_CNT	= 0x2708, | ||||||
|  | 	REG_UFS_HW_H8_EXIT_CNT			= 0x270C, | ||||||
|  | 	REG_UFS_SW_H8_EXIT_CNT			= 0x2710, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| enum { | enum { | ||||||
| 	UFS_MEM_CQIS_VS		= 0x8, | 	UFS_MEM_CQIS_VS		= 0x8, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -346,10 +346,9 @@ static_assert(sizeof(struct scsi_stream_status) == 8); | ||||||
| 
 | 
 | ||||||
| /* GET STREAM STATUS parameter data */ | /* GET STREAM STATUS parameter data */ | ||||||
| struct scsi_stream_status_header { | struct scsi_stream_status_header { | ||||||
| 	__be32 len;	/* length in bytes of stream_status[] array. */ | 	__be32 len;	/* length in bytes of following payload */ | ||||||
| 	u16 reserved; | 	u16 reserved; | ||||||
| 	__be16 number_of_open_streams; | 	__be16 number_of_open_streams; | ||||||
| 	DECLARE_FLEX_ARRAY(struct scsi_stream_status, stream_status); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static_assert(sizeof(struct scsi_stream_status_header) == 8); | static_assert(sizeof(struct scsi_stream_status_header) == 8); | ||||||
|  |  | ||||||
|  | @ -6,33 +6,29 @@ | ||||||
| #ifndef __QCOM_ICE_H__ | #ifndef __QCOM_ICE_H__ | ||||||
| #define __QCOM_ICE_H__ | #define __QCOM_ICE_H__ | ||||||
| 
 | 
 | ||||||
|  | #include <linux/blk-crypto.h> | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
| 
 | 
 | ||||||
| struct qcom_ice; | struct qcom_ice; | ||||||
| 
 | 
 | ||||||
| enum qcom_ice_crypto_key_size { |  | ||||||
| 	QCOM_ICE_CRYPTO_KEY_SIZE_INVALID	= 0x0, |  | ||||||
| 	QCOM_ICE_CRYPTO_KEY_SIZE_128		= 0x1, |  | ||||||
| 	QCOM_ICE_CRYPTO_KEY_SIZE_192		= 0x2, |  | ||||||
| 	QCOM_ICE_CRYPTO_KEY_SIZE_256		= 0x3, |  | ||||||
| 	QCOM_ICE_CRYPTO_KEY_SIZE_512		= 0x4, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| enum qcom_ice_crypto_alg { |  | ||||||
| 	QCOM_ICE_CRYPTO_ALG_AES_XTS		= 0x0, |  | ||||||
| 	QCOM_ICE_CRYPTO_ALG_BITLOCKER_AES_CBC	= 0x1, |  | ||||||
| 	QCOM_ICE_CRYPTO_ALG_AES_ECB		= 0x2, |  | ||||||
| 	QCOM_ICE_CRYPTO_ALG_ESSIV_AES_CBC	= 0x3, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| int qcom_ice_enable(struct qcom_ice *ice); | int qcom_ice_enable(struct qcom_ice *ice); | ||||||
| int qcom_ice_resume(struct qcom_ice *ice); | int qcom_ice_resume(struct qcom_ice *ice); | ||||||
| int qcom_ice_suspend(struct qcom_ice *ice); | int qcom_ice_suspend(struct qcom_ice *ice); | ||||||
| int qcom_ice_program_key(struct qcom_ice *ice, | int qcom_ice_program_key(struct qcom_ice *ice, unsigned int slot, | ||||||
| 			 u8 algorithm_id, u8 key_size, | 			 const struct blk_crypto_key *blk_key); | ||||||
| 			 const u8 crypto_key[], u8 data_unit_size, |  | ||||||
| 			 int slot); |  | ||||||
| int qcom_ice_evict_key(struct qcom_ice *ice, int slot); | int qcom_ice_evict_key(struct qcom_ice *ice, int slot); | ||||||
|  | enum blk_crypto_key_type qcom_ice_get_supported_key_type(struct qcom_ice *ice); | ||||||
|  | int qcom_ice_derive_sw_secret(struct qcom_ice *ice, | ||||||
|  | 			      const u8 *eph_key, size_t eph_key_size, | ||||||
|  | 			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); | ||||||
|  | int qcom_ice_generate_key(struct qcom_ice *ice, | ||||||
|  | 			  u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); | ||||||
|  | int qcom_ice_prepare_key(struct qcom_ice *ice, | ||||||
|  | 			 const u8 *lt_key, size_t lt_key_size, | ||||||
|  | 			 u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); | ||||||
|  | int qcom_ice_import_key(struct qcom_ice *ice, | ||||||
|  | 			const u8 *raw_key, size_t raw_key_size, | ||||||
|  | 			u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); | ||||||
| struct qcom_ice *devm_of_qcom_ice_get(struct device *dev); | struct qcom_ice *devm_of_qcom_ice_get(struct device *dev); | ||||||
| 
 | 
 | ||||||
| #endif /* __QCOM_ICE_H__ */ | #endif /* __QCOM_ICE_H__ */ | ||||||
|  |  | ||||||
|  | @ -157,6 +157,7 @@ enum se_cmd_flags_table { | ||||||
| 	SCF_USE_CPUID				= (1 << 16), | 	SCF_USE_CPUID				= (1 << 16), | ||||||
| 	SCF_TASK_ATTR_SET			= (1 << 17), | 	SCF_TASK_ATTR_SET			= (1 << 17), | ||||||
| 	SCF_TREAT_READ_AS_NORMAL		= (1 << 18), | 	SCF_TREAT_READ_AS_NORMAL		= (1 << 18), | ||||||
|  | 	SCF_TASK_ORDERED_SYNC			= (1 << 19), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -669,15 +670,19 @@ struct se_lun_acl { | ||||||
| 	struct se_ml_stat_grps	ml_stat_grps; | 	struct se_ml_stat_grps	ml_stat_grps; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct se_dev_entry_io_stats { | ||||||
|  | 	u32			total_cmds; | ||||||
|  | 	u32			read_bytes; | ||||||
|  | 	u32			write_bytes; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct se_dev_entry { | struct se_dev_entry { | ||||||
| 	u64			mapped_lun; | 	u64			mapped_lun; | ||||||
| 	u64			pr_res_key; | 	u64			pr_res_key; | ||||||
| 	u64			creation_time; | 	u64			creation_time; | ||||||
| 	bool			lun_access_ro; | 	bool			lun_access_ro; | ||||||
| 	u32			attach_count; | 	u32			attach_count; | ||||||
| 	atomic_long_t		total_cmds; | 	struct se_dev_entry_io_stats __percpu	*stats; | ||||||
| 	atomic_long_t		read_bytes; |  | ||||||
| 	atomic_long_t		write_bytes; |  | ||||||
| 	/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ | 	/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ | ||||||
| 	struct kref		pr_kref; | 	struct kref		pr_kref; | ||||||
| 	struct completion	pr_comp; | 	struct completion	pr_comp; | ||||||
|  | @ -800,6 +805,12 @@ struct se_device_queue { | ||||||
| 	struct se_cmd_queue	sq; | 	struct se_cmd_queue	sq; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct se_dev_io_stats { | ||||||
|  | 	u32			total_cmds; | ||||||
|  | 	u32			read_bytes; | ||||||
|  | 	u32			write_bytes; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct se_device { | struct se_device { | ||||||
| 	/* Used for SAM Task Attribute ordering */ | 	/* Used for SAM Task Attribute ordering */ | ||||||
| 	u32			dev_cur_ordered_id; | 	u32			dev_cur_ordered_id; | ||||||
|  | @ -821,13 +832,10 @@ struct se_device { | ||||||
| 	atomic_long_t		num_resets; | 	atomic_long_t		num_resets; | ||||||
| 	atomic_long_t		aborts_complete; | 	atomic_long_t		aborts_complete; | ||||||
| 	atomic_long_t		aborts_no_task; | 	atomic_long_t		aborts_no_task; | ||||||
| 	atomic_long_t		num_cmds; | 	struct se_dev_io_stats __percpu	*stats; | ||||||
| 	atomic_long_t		read_bytes; |  | ||||||
| 	atomic_long_t		write_bytes; |  | ||||||
| 	/* Active commands on this virtual SE device */ | 	/* Active commands on this virtual SE device */ | ||||||
| 	atomic_t		non_ordered; | 	struct percpu_ref	non_ordered; | ||||||
| 	bool			ordered_sync_in_progress; | 	bool			ordered_sync_in_progress; | ||||||
| 	atomic_t		delayed_cmd_count; |  | ||||||
| 	atomic_t		dev_qf_count; | 	atomic_t		dev_qf_count; | ||||||
| 	u32			export_count; | 	u32			export_count; | ||||||
| 	spinlock_t		delayed_cmd_lock; | 	spinlock_t		delayed_cmd_lock; | ||||||
|  | @ -890,7 +898,7 @@ struct target_opcode_descriptor { | ||||||
| 	u8			specific_timeout; | 	u8			specific_timeout; | ||||||
| 	u16			nominal_timeout; | 	u16			nominal_timeout; | ||||||
| 	u16			recommended_timeout; | 	u16			recommended_timeout; | ||||||
| 	bool			(*enabled)(struct target_opcode_descriptor *descr, | 	bool			(*enabled)(const struct target_opcode_descriptor *descr, | ||||||
| 					   struct se_cmd *cmd); | 					   struct se_cmd *cmd); | ||||||
| 	void			(*update_usage_bits)(u8 *usage_bits, | 	void			(*update_usage_bits)(u8 *usage_bits, | ||||||
| 						     struct se_device *dev); | 						     struct se_device *dev); | ||||||
|  |  | ||||||
|  | @ -182,6 +182,9 @@ enum attr_idn { | ||||||
| 	QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE        = 0x1F, | 	QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE        = 0x1F, | ||||||
| 	QUERY_ATTR_IDN_TIMESTAMP		= 0x30, | 	QUERY_ATTR_IDN_TIMESTAMP		= 0x30, | ||||||
| 	QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID     = 0x34, | 	QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID     = 0x34, | ||||||
|  | 	QUERY_ATTR_IDN_WB_BUF_RESIZE_HINT	= 0x3C, | ||||||
|  | 	QUERY_ATTR_IDN_WB_BUF_RESIZE_EN		= 0x3D, | ||||||
|  | 	QUERY_ATTR_IDN_WB_BUF_RESIZE_STATUS	= 0x3E, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* Descriptor idn for Query requests */ | /* Descriptor idn for Query requests */ | ||||||
|  | @ -290,6 +293,7 @@ enum device_desc_param { | ||||||
| 	DEVICE_DESC_PARAM_PRDCT_REV		= 0x2A, | 	DEVICE_DESC_PARAM_PRDCT_REV		= 0x2A, | ||||||
| 	DEVICE_DESC_PARAM_HPB_VER		= 0x40, | 	DEVICE_DESC_PARAM_HPB_VER		= 0x40, | ||||||
| 	DEVICE_DESC_PARAM_HPB_CONTROL		= 0x42, | 	DEVICE_DESC_PARAM_HPB_CONTROL		= 0x42, | ||||||
|  | 	DEVICE_DESC_PARAM_EXT_WB_SUP		= 0x4D, | ||||||
| 	DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP	= 0x4F, | 	DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP	= 0x4F, | ||||||
| 	DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN	= 0x53, | 	DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN	= 0x53, | ||||||
| 	DEVICE_DESC_PARAM_WB_TYPE		= 0x54, | 	DEVICE_DESC_PARAM_WB_TYPE		= 0x54, | ||||||
|  | @ -384,6 +388,11 @@ enum { | ||||||
| 	UFSHCD_AMP		= 3, | 	UFSHCD_AMP		= 3, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* Possible values for wExtendedWriteBoosterSupport */ | ||||||
|  | enum { | ||||||
|  | 	UFS_DEV_WB_BUF_RESIZE	= BIT(0), | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /* Possible values for dExtendedUFSFeaturesSupport */ | /* Possible values for dExtendedUFSFeaturesSupport */ | ||||||
| enum { | enum { | ||||||
| 	UFS_DEV_HIGH_TEMP_NOTIF		= BIT(4), | 	UFS_DEV_HIGH_TEMP_NOTIF		= BIT(4), | ||||||
|  | @ -457,6 +466,28 @@ enum ufs_ref_clk_freq { | ||||||
| 	REF_CLK_FREQ_INVAL	= -1, | 	REF_CLK_FREQ_INVAL	= -1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* bWriteBoosterBufferResizeEn attribute */ | ||||||
|  | enum wb_resize_en { | ||||||
|  | 	WB_RESIZE_EN_IDLE	= 0, | ||||||
|  | 	WB_RESIZE_EN_DECREASE	= 1, | ||||||
|  | 	WB_RESIZE_EN_INCREASE	= 2, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* bWriteBoosterBufferResizeHint attribute */ | ||||||
|  | enum wb_resize_hint { | ||||||
|  | 	WB_RESIZE_HINT_KEEP	= 0, | ||||||
|  | 	WB_RESIZE_HINT_DECREASE	= 1, | ||||||
|  | 	WB_RESIZE_HINT_INCREASE	= 2, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* bWriteBoosterBufferResizeStatus attribute */ | ||||||
|  | enum wb_resize_status { | ||||||
|  | 	WB_RESIZE_STATUS_IDLE	= 0, | ||||||
|  | 	WB_RESIZE_STATUS_IN_PROGRESS	= 1, | ||||||
|  | 	WB_RESIZE_STATUS_COMPLETE_SUCCESS	= 2, | ||||||
|  | 	WB_RESIZE_STATUS_GENERAL_FAILURE	= 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /* Query response result code */ | /* Query response result code */ | ||||||
| enum { | enum { | ||||||
| 	QUERY_RESULT_SUCCESS                    = 0x00, | 	QUERY_RESULT_SUCCESS                    = 0x00, | ||||||
|  | @ -581,6 +612,7 @@ struct ufs_dev_info { | ||||||
| 	bool    wb_buf_flush_enabled; | 	bool    wb_buf_flush_enabled; | ||||||
| 	u8	wb_dedicated_lu; | 	u8	wb_dedicated_lu; | ||||||
| 	u8      wb_buffer_type; | 	u8      wb_buffer_type; | ||||||
|  | 	u16	ext_wb_sup; | ||||||
| 
 | 
 | ||||||
| 	bool	b_rpm_dev_flush_capable; | 	bool	b_rpm_dev_flush_capable; | ||||||
| 	u8	b_presrv_uspc_en; | 	u8	b_presrv_uspc_en; | ||||||
|  |  | ||||||
|  | @ -501,8 +501,6 @@ struct ufs_event_hist { | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct ufs_stats - keeps usage/err statistics |  * struct ufs_stats - keeps usage/err statistics | ||||||
|  * @last_intr_status: record the last interrupt status. |  | ||||||
|  * @last_intr_ts: record the last interrupt timestamp. |  | ||||||
|  * @hibern8_exit_cnt: Counter to keep track of number of exits, |  * @hibern8_exit_cnt: Counter to keep track of number of exits, | ||||||
|  *		reset this after link-startup. |  *		reset this after link-startup. | ||||||
|  * @last_hibern8_exit_tstamp: Set time after the hibern8 exit. |  * @last_hibern8_exit_tstamp: Set time after the hibern8 exit. | ||||||
|  | @ -510,9 +508,6 @@ struct ufs_event_hist { | ||||||
|  * @event: array with event history. |  * @event: array with event history. | ||||||
|  */ |  */ | ||||||
| struct ufs_stats { | struct ufs_stats { | ||||||
| 	u32 last_intr_status; |  | ||||||
| 	u64 last_intr_ts; |  | ||||||
| 
 |  | ||||||
| 	u32 hibern8_exit_cnt; | 	u32 hibern8_exit_cnt; | ||||||
| 	u64 last_hibern8_exit_tstamp; | 	u64 last_hibern8_exit_tstamp; | ||||||
| 	struct ufs_event_hist event[UFS_EVT_CNT]; | 	struct ufs_event_hist event[UFS_EVT_CNT]; | ||||||
|  | @ -959,6 +954,7 @@ enum ufshcd_mcq_opr { | ||||||
|  *	ufshcd_resume_complete() |  *	ufshcd_resume_complete() | ||||||
|  * @mcq_sup: is mcq supported by UFSHC |  * @mcq_sup: is mcq supported by UFSHC | ||||||
|  * @mcq_enabled: is mcq ready to accept requests |  * @mcq_enabled: is mcq ready to accept requests | ||||||
|  |  * @mcq_esi_enabled: is mcq ESI configured | ||||||
|  * @res: array of resource info of MCQ registers |  * @res: array of resource info of MCQ registers | ||||||
|  * @mcq_base: Multi circular queue registers base address |  * @mcq_base: Multi circular queue registers base address | ||||||
|  * @uhq: array of supported hardware queues |  * @uhq: array of supported hardware queues | ||||||
|  | @ -1130,6 +1126,7 @@ struct ufs_hba { | ||||||
| 	bool mcq_sup; | 	bool mcq_sup; | ||||||
| 	bool lsdb_sup; | 	bool lsdb_sup; | ||||||
| 	bool mcq_enabled; | 	bool mcq_enabled; | ||||||
|  | 	bool mcq_esi_enabled; | ||||||
| 	struct ufshcd_res_info res[RES_MAX]; | 	struct ufshcd_res_info res[RES_MAX]; | ||||||
| 	void __iomem *mcq_base; | 	void __iomem *mcq_base; | ||||||
| 	struct ufs_hw_queue *uhq; | 	struct ufs_hw_queue *uhq; | ||||||
|  | @ -1476,6 +1473,7 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r | ||||||
| 				     struct scatterlist *sg_list, enum dma_data_direction dir); | 				     struct scatterlist *sg_list, enum dma_data_direction dir); | ||||||
| int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable); | int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable); | ||||||
| int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable); | int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable); | ||||||
|  | int ufshcd_wb_set_resize_en(struct ufs_hba *hba, enum wb_resize_en en_mode); | ||||||
| int ufshcd_suspend_prepare(struct device *dev); | int ufshcd_suspend_prepare(struct device *dev); | ||||||
| int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm); | int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm); | ||||||
| void ufshcd_resume_complete(struct device *dev); | void ufshcd_resume_complete(struct device *dev); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds