Skip to content

Commit fa03dd2

Browse files
Chandrakanth Patilroot
authored andcommitted
scsi: mpt3sas: Add support for MCTP Passthrough commands
JIRA: https://issues.redhat.com/browse/RHEL-81907 The MPI specification defines support for sending MCTP management commands as a passthrough function to the IOC. Add support for driver to discover the IOC capability to support MCTP passthrough function. Driver will support applications and kernel modules to send MPT commands containing the MCTP passthrough request to firmware through an MPI request. Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com> Signed-off-by: Sathya Prakash <sathya.prakash@broadcom.com> Link: https://lore.kernel.org/r/1739410016-27503-3-git-send-email-shivasharan.srikanteshwara@broadcom.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> (cherry picked from commit c72be4b) Signed-off-by: Chandrakanth Patil <chanpati@redhat.com>
1 parent f8393db commit fa03dd2

File tree

3 files changed

+318
-0
lines changed

3 files changed

+318
-0
lines changed

drivers/scsi/mpt3sas/mpt3sas_base.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,11 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
12021202
ioc->sge_size;
12031203
func_str = "nvme_encapsulated";
12041204
break;
1205+
case MPI2_FUNCTION_MCTP_PASSTHROUGH:
1206+
frame_sz = sizeof(Mpi26MctpPassthroughRequest_t) +
1207+
ioc->sge_size;
1208+
func_str = "mctp_passthru";
1209+
break;
12051210
default:
12061211
frame_sz = 32;
12071212
func_str = "unknown";
@@ -4874,6 +4879,12 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
48744879
i++;
48754880
}
48764881

4882+
if (ioc->facts.IOCCapabilities &
4883+
MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) {
4884+
pr_cont("%sMCTP Passthru", i ? "," : "");
4885+
i++;
4886+
}
4887+
48774888
iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
48784889
if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
48794890
pr_cont("%sNCQ", i ? "," : "");

drivers/scsi/mpt3sas/mpt3sas_ctl.c

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
186186
case MPI2_FUNCTION_NVME_ENCAPSULATED:
187187
desc = "nvme_encapsulated";
188188
break;
189+
case MPI2_FUNCTION_MCTP_PASSTHROUGH:
190+
desc = "mctp_passthrough";
191+
break;
189192
}
190193

191194
if (!desc)
@@ -652,6 +655,40 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg,
652655
return 0;
653656
}
654657

658+
/**
659+
* _ctl_send_mctp_passthru_req - Send an MCTP passthru request
660+
* @ioc: per adapter object
661+
* @mctp_passthru_req: MPI mctp passhthru request from caller
662+
* @psge: pointer to the H2DSGL
663+
* @data_out_dma: DMA buffer for H2D SGL
664+
* @data_out_sz: H2D length
665+
* @data_in_dma: DMA buffer for D2H SGL
666+
* @data_in_sz: D2H length
667+
* @smid: SMID to submit the request
668+
*
669+
*/
670+
static void
671+
_ctl_send_mctp_passthru_req(
672+
struct MPT3SAS_ADAPTER *ioc,
673+
Mpi26MctpPassthroughRequest_t *mctp_passthru_req, void *psge,
674+
dma_addr_t data_out_dma, int data_out_sz,
675+
dma_addr_t data_in_dma, int data_in_sz,
676+
u16 smid)
677+
{
678+
mctp_passthru_req->H2DLength = data_out_sz;
679+
mctp_passthru_req->D2HLength = data_in_sz;
680+
681+
/* Build the H2D SGL from the data out buffer */
682+
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, 0, 0);
683+
684+
psge += ioc->sge_size_ieee;
685+
686+
/* Build the D2H SGL for the data in buffer */
687+
ioc->build_sg(ioc, psge, 0, 0, data_in_dma, data_in_sz);
688+
689+
ioc->put_smid_default(ioc, smid);
690+
}
691+
655692
/**
656693
* _ctl_do_mpt_command - main handler for MPT3COMMAND opcode
657694
* @ioc: per adapter object
@@ -792,6 +829,23 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
792829

793830
init_completion(&ioc->ctl_cmds.done);
794831
switch (mpi_request->Function) {
832+
case MPI2_FUNCTION_MCTP_PASSTHROUGH:
833+
{
834+
Mpi26MctpPassthroughRequest_t *mctp_passthru_req =
835+
(Mpi26MctpPassthroughRequest_t *)request;
836+
837+
if (!(ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU)) {
838+
ioc_err(ioc, "%s: MCTP Passthrough request not supported\n",
839+
__func__);
840+
mpt3sas_base_free_smid(ioc, smid);
841+
ret = -EINVAL;
842+
goto out;
843+
}
844+
845+
_ctl_send_mctp_passthru_req(ioc, mctp_passthru_req, psge, data_out_dma,
846+
data_out_sz, data_in_dma, data_in_sz, smid);
847+
break;
848+
}
795849
case MPI2_FUNCTION_NVME_ENCAPSULATED:
796850
{
797851
nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request;
@@ -2786,6 +2840,217 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
27862840
return ret;
27872841
}
27882842

2843+
/**
2844+
* _ctl_get_mpt_mctp_passthru_adapter - Traverse the IOC list and return the IOC at
2845+
* dev_index positionthat support MCTP passhtru
2846+
* @dev_index: position in the mpt3sas_ioc_list to search for
2847+
* Return pointer to the IOC on success
2848+
* NULL if device not found error
2849+
*/
2850+
static struct MPT3SAS_ADAPTER *
2851+
_ctl_get_mpt_mctp_passthru_adapter(int dev_index)
2852+
{
2853+
struct MPT3SAS_ADAPTER *ioc = NULL;
2854+
int count = 0;
2855+
2856+
spin_lock(&gioc_lock);
2857+
/* Traverse ioc list and return number of IOC that support MCTP passthru */
2858+
list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
2859+
if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) {
2860+
if (count == dev_index) {
2861+
spin_unlock(&gioc_lock);
2862+
return 0;
2863+
}
2864+
}
2865+
}
2866+
spin_unlock(&gioc_lock);
2867+
2868+
return NULL;
2869+
}
2870+
2871+
/**
2872+
* mpt3sas_get_device_count - Retrieve the count of MCTP passthrough
2873+
* capable devices managed by the driver.
2874+
*
2875+
* Returns number of devices that support MCTP passthrough.
2876+
*/
2877+
int
2878+
mpt3sas_get_device_count(void)
2879+
{
2880+
int count = 0;
2881+
struct MPT3SAS_ADAPTER *ioc = NULL;
2882+
2883+
spin_lock(&gioc_lock);
2884+
/* Traverse ioc list and return number of IOC that support MCTP passthru */
2885+
list_for_each_entry(ioc, &mpt3sas_ioc_list, list)
2886+
if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU)
2887+
count++;
2888+
2889+
spin_unlock(&gioc_lock);
2890+
2891+
return count;
2892+
}
2893+
EXPORT_SYMBOL(mpt3sas_get_device_count);
2894+
2895+
/**
2896+
* mpt3sas_send_passthru_cmd - Send an MPI MCTP passthrough command to
2897+
* firmware
2898+
* @command: The MPI MCTP passthrough command to send to firmware
2899+
*
2900+
* Returns 0 on success, anything else is error.
2901+
*/
2902+
int mpt3sas_send_mctp_passthru_req(struct mpt3_passthru_command *command)
2903+
{
2904+
struct MPT3SAS_ADAPTER *ioc;
2905+
MPI2RequestHeader_t *mpi_request = NULL, *request;
2906+
MPI2DefaultReply_t *mpi_reply;
2907+
Mpi26MctpPassthroughRequest_t *mctp_passthru_req;
2908+
u16 smid;
2909+
unsigned long timeout;
2910+
u8 issue_reset = 0;
2911+
u32 sz;
2912+
void *psge;
2913+
void *data_out = NULL;
2914+
dma_addr_t data_out_dma = 0;
2915+
size_t data_out_sz = 0;
2916+
void *data_in = NULL;
2917+
dma_addr_t data_in_dma = 0;
2918+
size_t data_in_sz = 0;
2919+
long ret;
2920+
2921+
/* Retrieve ioc from dev_index */
2922+
ioc = _ctl_get_mpt_mctp_passthru_adapter(command->dev_index);
2923+
if (!ioc)
2924+
return -ENODEV;
2925+
2926+
mutex_lock(&ioc->pci_access_mutex);
2927+
if (ioc->shost_recovery ||
2928+
ioc->pci_error_recovery || ioc->is_driver_loading ||
2929+
ioc->remove_host) {
2930+
ret = -EAGAIN;
2931+
goto unlock_pci_access;
2932+
}
2933+
2934+
/* Lock the ctl_cmds mutex to ensure a single ctl cmd is pending */
2935+
if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) {
2936+
ret = -ERESTARTSYS;
2937+
goto unlock_pci_access;
2938+
}
2939+
2940+
if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
2941+
ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
2942+
ret = -EAGAIN;
2943+
goto unlock_ctl_cmds;
2944+
}
2945+
2946+
ret = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);
2947+
if (ret)
2948+
goto unlock_ctl_cmds;
2949+
2950+
mpi_request = (MPI2RequestHeader_t *)command->mpi_request;
2951+
if (mpi_request->Function != MPI2_FUNCTION_MCTP_PASSTHROUGH) {
2952+
ioc_err(ioc, "%s: Invalid request receveid, Function 0x%x\n",
2953+
__func__, mpi_request->Function);
2954+
ret = -EINVAL;
2955+
goto unlock_ctl_cmds;
2956+
}
2957+
2958+
/* Use first reserved smid for passthrough commands */
2959+
smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1;
2960+
ret = 0;
2961+
ioc->ctl_cmds.status = MPT3_CMD_PENDING;
2962+
memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
2963+
request = mpt3sas_base_get_msg_frame(ioc, smid);
2964+
memset(request, 0, ioc->request_sz);
2965+
memcpy(request, command->mpi_request, sizeof(Mpi26MctpPassthroughRequest_t));
2966+
ioc->ctl_cmds.smid = smid;
2967+
data_out_sz = command->data_out_size;
2968+
data_in_sz = command->data_in_size;
2969+
2970+
/* obtain dma-able memory for data transfer */
2971+
if (data_out_sz) /* WRITE */ {
2972+
data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz,
2973+
&data_out_dma, GFP_ATOMIC);
2974+
if (!data_out) {
2975+
ret = -ENOMEM;
2976+
mpt3sas_base_free_smid(ioc, smid);
2977+
goto out;
2978+
}
2979+
memcpy(data_out, command->data_out_buf_ptr, data_out_sz);
2980+
2981+
}
2982+
2983+
if (data_in_sz) /* READ */ {
2984+
data_in = dma_alloc_coherent(&ioc->pdev->dev, data_in_sz,
2985+
&data_in_dma, GFP_ATOMIC);
2986+
if (!data_in) {
2987+
ret = -ENOMEM;
2988+
mpt3sas_base_free_smid(ioc, smid);
2989+
goto out;
2990+
}
2991+
}
2992+
2993+
psge = &((Mpi26MctpPassthroughRequest_t *)request)->H2DSGL;
2994+
2995+
init_completion(&ioc->ctl_cmds.done);
2996+
2997+
mctp_passthru_req = (Mpi26MctpPassthroughRequest_t *)request;
2998+
2999+
_ctl_send_mctp_passthru_req(ioc, mctp_passthru_req, psge, data_out_dma,
3000+
data_out_sz, data_in_dma, data_in_sz, smid);
3001+
3002+
timeout = command->timeout;
3003+
if (timeout < MPT3_IOCTL_DEFAULT_TIMEOUT)
3004+
timeout = MPT3_IOCTL_DEFAULT_TIMEOUT;
3005+
3006+
wait_for_completion_timeout(&ioc->ctl_cmds.done, timeout*HZ);
3007+
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
3008+
mpt3sas_check_cmd_timeout(ioc,
3009+
ioc->ctl_cmds.status, mpi_request,
3010+
sizeof(Mpi26MctpPassthroughRequest_t), issue_reset);
3011+
goto issue_host_reset;
3012+
}
3013+
3014+
mpi_reply = ioc->ctl_cmds.reply;
3015+
3016+
/* copy out xdata to user */
3017+
if (data_in_sz)
3018+
memcpy(command->data_in_buf_ptr, data_in, data_in_sz);
3019+
3020+
/* copy out reply message frame to user */
3021+
if (command->max_reply_bytes) {
3022+
sz = min_t(u32, command->max_reply_bytes, ioc->reply_sz);
3023+
memcpy(command->reply_frame_buf_ptr, ioc->ctl_cmds.reply, sz);
3024+
}
3025+
3026+
issue_host_reset:
3027+
if (issue_reset) {
3028+
ret = -ENODATA;
3029+
mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
3030+
}
3031+
3032+
out:
3033+
/* free memory associated with sg buffers */
3034+
if (data_in)
3035+
dma_free_coherent(&ioc->pdev->dev, data_in_sz, data_in,
3036+
data_in_dma);
3037+
3038+
if (data_out)
3039+
dma_free_coherent(&ioc->pdev->dev, data_out_sz, data_out,
3040+
data_out_dma);
3041+
3042+
ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
3043+
3044+
unlock_ctl_cmds:
3045+
mutex_unlock(&ioc->ctl_cmds.mutex);
3046+
3047+
unlock_pci_access:
3048+
mutex_unlock(&ioc->pci_access_mutex);
3049+
return ret;
3050+
3051+
}
3052+
EXPORT_SYMBOL(mpt3sas_send_mctp_passthru_req);
3053+
27893054
/**
27903055
* _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked)
27913056
* @file: (struct file)

drivers/scsi/mpt3sas/mpt3sas_ctl.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,4 +458,46 @@ struct mpt3_enable_diag_sbr_reload {
458458
struct mpt3_ioctl_header hdr;
459459
};
460460

461+
/**
462+
* struct mpt3_passthru_command - generic mpt firmware passthru command
463+
* @dev_index - device index
464+
* @timeout - command timeout in seconds. (if zero then use driver default
465+
* value).
466+
* @reply_frame_buf_ptr - MPI reply location
467+
* @data_in_buf_ptr - destination for read
468+
* @data_out_buf_ptr - data source for write
469+
* @max_reply_bytes - maximum number of reply bytes to be sent to app.
470+
* @data_in_size - number bytes for data transfer in (read)
471+
* @data_out_size - number bytes for data transfer out (write)
472+
* @mpi_request - request frame
473+
*/
474+
struct mpt3_passthru_command {
475+
u8 dev_index;
476+
uint32_t timeout;
477+
void *reply_frame_buf_ptr;
478+
void *data_in_buf_ptr;
479+
void *data_out_buf_ptr;
480+
uint32_t max_reply_bytes;
481+
uint32_t data_in_size;
482+
uint32_t data_out_size;
483+
Mpi26MctpPassthroughRequest_t *mpi_request;
484+
};
485+
486+
/*
487+
* mpt3sas_get_device_count - Retrieve the count of MCTP passthrough
488+
* capable devices managed by the driver.
489+
*
490+
* Returns number of devices that support MCTP passthrough.
491+
*/
492+
int mpt3sas_get_device_count(void);
493+
494+
/*
495+
* mpt3sas_send_passthru_cmd - Send an MPI MCTP passthrough command to
496+
* firmware
497+
* @command: The MPI MCTP passthrough command to send to firmware
498+
*
499+
* Returns 0 on success, anything else is error .
500+
*/
501+
int mpt3sas_send_mctp_passthru_req(struct mpt3_passthru_command *command);
502+
461503
#endif /* MPT3SAS_CTL_H_INCLUDED */

0 commit comments

Comments
 (0)