Commit 824a1566 authored by Kashyap Desai's avatar Kashyap Desai Committed by Martin K. Petersen

scsi: mpi3mr: Base driver code

Implement basic pci device driver requirements: Device probing, memory
allocation, mapping system registers, allocate irq lines, etc.

Source is managed in mainly three different files:

 - mpi3mr_fw.c:  Common code which interacts with underlying fw/hw.

 - mpi3mr_os.c:  Common code which interacts with SCSI midlayer.

 - mpi3mr_app.c: Common code which interacts with application/ioctl.
		 This is currently work in progress.

Link: https://lore.kernel.org/r/20210520152545.2710479-3-kashyap.desai@broadcom.com
Cc: sathya.prakash@broadcom.com
Cc: bvanassche@acm.org
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Reviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: default avatarKashyap Desai <kashyap.desai@broadcom.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c4f7ac64
# mpi3mr makefile
obj-m += mpi3mr.o
mpi3mr-y += mpi3mr_os.o \
mpi3mr_fw.o \
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for Broadcom MPI3 Storage Controllers
*
* Copyright (C) 2017-2021 Broadcom Inc.
* (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
*
*/
#ifndef MPI3SAS_DEBUG_H_INCLUDED
#define MPI3SAS_DEBUG_H_INCLUDED
/*
* debug levels
*/
#define MPI3_DEBUG 0x00000001
#define MPI3_DEBUG_MSG_FRAME 0x00000002
#define MPI3_DEBUG_SG 0x00000004
#define MPI3_DEBUG_EVENTS 0x00000008
#define MPI3_DEBUG_EVENT_WORK_TASK 0x00000010
#define MPI3_DEBUG_INIT 0x00000020
#define MPI3_DEBUG_EXIT 0x00000040
#define MPI3_DEBUG_FAIL 0x00000080
#define MPI3_DEBUG_TM 0x00000100
#define MPI3_DEBUG_REPLY 0x00000200
#define MPI3_DEBUG_HANDSHAKE 0x00000400
#define MPI3_DEBUG_CONFIG 0x00000800
#define MPI3_DEBUG_DL 0x00001000
#define MPI3_DEBUG_RESET 0x00002000
#define MPI3_DEBUG_SCSI 0x00004000
#define MPI3_DEBUG_IOCTL 0x00008000
#define MPI3_DEBUG_CSMISAS 0x00010000
#define MPI3_DEBUG_SAS 0x00020000
#define MPI3_DEBUG_TRANSPORT 0x00040000
#define MPI3_DEBUG_TASK_SET_FULL 0x00080000
#define MPI3_DEBUG_TRIGGER_DIAG 0x00200000
/*
* debug macros
*/
#define ioc_err(ioc, fmt, ...) \
pr_err("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
#define ioc_notice(ioc, fmt, ...) \
pr_notice("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
#define ioc_warn(ioc, fmt, ...) \
pr_warn("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
#define ioc_info(ioc, fmt, ...) \
pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
#define dbgprint(IOC, FMT, ...) \
do { \
if (IOC->logging_level & MPI3_DEBUG) \
pr_info("%s: " FMT, (IOC)->name, ##__VA_ARGS__); \
} while (0)
#endif /* MPT3SAS_DEBUG_H_INCLUDED */
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for Broadcom MPI3 Storage Controllers
*
* Copyright (C) 2017-2021 Broadcom Inc.
* (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
*
*/
#include "mpi3mr.h"
/* global driver scop variables */
LIST_HEAD(mrioc_list);
DEFINE_SPINLOCK(mrioc_list_lock);
static int mrioc_ids;
static int warn_non_secure_ctlr;
MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
MODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
MODULE_VERSION(MPI3MR_DRIVER_VERSION);
/* Module parameters*/
int logging_level;
module_param(logging_level, int, 0);
MODULE_PARM_DESC(logging_level,
" bits for enabling additional logging info (default=0)");
/**
* mpi3mr_map_queues - Map queues callback handler
* @shost: SCSI host reference
*
* Call the blk_mq_pci_map_queues with from which operational
* queue the mapping has to be done
*
* Return: return of blk_mq_pci_map_queues
*/
static int mpi3mr_map_queues(struct Scsi_Host *shost)
{
struct mpi3mr_ioc *mrioc = shost_priv(shost);
return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
mrioc->pdev, 0);
}
/**
* mpi3mr_slave_destroy - Slave destroy callback handler
* @sdev: SCSI device reference
*
* Cleanup and free per device(lun) private data.
*
* Return: Nothing.
*/
static void mpi3mr_slave_destroy(struct scsi_device *sdev)
{
}
/**
* mpi3mr_target_destroy - Target destroy callback handler
* @starget: SCSI target reference
*
* Cleanup and free per target private data.
*
* Return: Nothing.
*/
static void mpi3mr_target_destroy(struct scsi_target *starget)
{
}
/**
* mpi3mr_slave_configure - Slave configure callback handler
* @sdev: SCSI device reference
*
* Configure queue depth, max hardware sectors and virt boundary
* as required
*
* Return: 0 always.
*/
static int mpi3mr_slave_configure(struct scsi_device *sdev)
{
int retval = 0;
return retval;
}
/**
* mpi3mr_slave_alloc -Slave alloc callback handler
* @sdev: SCSI device reference
*
* Allocate per device(lun) private data and initialize it.
*
* Return: 0 on success -ENOMEM on memory allocation failure.
*/
static int mpi3mr_slave_alloc(struct scsi_device *sdev)
{
int retval = 0;
return retval;
}
/**
* mpi3mr_target_alloc - Target alloc callback handler
* @starget: SCSI target reference
*
* Allocate per target private data and initialize it.
*
* Return: 0 on success -ENOMEM on memory allocation failure.
*/
static int mpi3mr_target_alloc(struct scsi_target *starget)
{
int retval = -ENODEV;
return retval;
}
/**
* mpi3mr_qcmd - I/O request despatcher
* @shost: SCSI Host reference
* @scmd: SCSI Command reference
*
* Issues the SCSI Command as an MPI3 request.
*
* Return: 0 on successful queueing of the request or if the
* request is completed with failure.
* SCSI_MLQUEUE_DEVICE_BUSY when the device is busy.
* SCSI_MLQUEUE_HOST_BUSY when the host queue is full.
*/
static int mpi3mr_qcmd(struct Scsi_Host *shost,
struct scsi_cmnd *scmd)
{
int retval = 0;
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return retval;
}
static struct scsi_host_template mpi3mr_driver_template = {
.module = THIS_MODULE,
.name = "MPI3 Storage Controller",
.proc_name = MPI3MR_DRIVER_NAME,
.queuecommand = mpi3mr_qcmd,
.target_alloc = mpi3mr_target_alloc,
.slave_alloc = mpi3mr_slave_alloc,
.slave_configure = mpi3mr_slave_configure,
.target_destroy = mpi3mr_target_destroy,
.slave_destroy = mpi3mr_slave_destroy,
.map_queues = mpi3mr_map_queues,
.no_write_same = 1,
.can_queue = 1,
.this_id = -1,
.sg_tablesize = MPI3MR_SG_DEPTH,
/* max xfer supported is 1M (2K in 512 byte sized sectors)
*/
.max_sectors = 2048,
.cmd_per_lun = MPI3MR_MAX_CMDS_LUN,
.track_queue_depth = 1,
.cmd_size = sizeof(struct scmd_priv),
};
/**
* mpi3mr_init_drv_cmd - Initialize internal command tracker
* @cmdptr: Internal command tracker
* @host_tag: Host tag used for the specific command
*
* Initialize the internal command tracker structure with
* specified host tag.
*
* Return: Nothing.
*/
static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
u16 host_tag)
{
mutex_init(&cmdptr->mutex);
cmdptr->reply = NULL;
cmdptr->state = MPI3MR_CMD_NOTUSED;
cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
cmdptr->host_tag = host_tag;
}
/**
* mpi3mr_probe - PCI probe callback
* @pdev: PCI device instance
* @id: PCI device ID details
*
* controller initialization routine. Checks the security status
* of the controller and if it is invalid or tampered return the
* probe without initializing the controller. Otherwise,
* allocate per adapter instance through shost_priv and
* initialize controller specific data structures, initializae
* the controller hardware, add shost to the SCSI subsystem.
*
* Return: 0 on success, non-zero on failure.
*/
static int
mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct mpi3mr_ioc *mrioc = NULL;
struct Scsi_Host *shost = NULL;
int retval = 0;
shost = scsi_host_alloc(&mpi3mr_driver_template,
sizeof(struct mpi3mr_ioc));
if (!shost) {
retval = -ENODEV;
goto shost_failed;
}
mrioc = shost_priv(shost);
mrioc->id = mrioc_ids++;
sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME);
sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id);
INIT_LIST_HEAD(&mrioc->list);
spin_lock(&mrioc_list_lock);
list_add_tail(&mrioc->list, &mrioc_list);
spin_unlock(&mrioc_list_lock);
spin_lock_init(&mrioc->admin_req_lock);
spin_lock_init(&mrioc->reply_free_queue_lock);
spin_lock_init(&mrioc->sbq_lock);
mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
mrioc->logging_level = logging_level;
mrioc->shost = shost;
mrioc->pdev = pdev;
/* init shost parameters */
shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
shost->max_lun = -1;
shost->unique_id = mrioc->id;
shost->max_channel = 1;
shost->max_id = 0xFFFFFFFF;
mrioc->is_driver_loading = 1;
if (mpi3mr_init_ioc(mrioc)) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
retval = -ENODEV;
goto out_iocinit_failed;
}
shost->nr_hw_queues = mrioc->num_op_reply_q;
shost->can_queue = mrioc->max_host_ios;
shost->sg_tablesize = MPI3MR_SG_DEPTH;
shost->max_id = mrioc->facts.max_perids;
retval = scsi_add_host(shost, &pdev->dev);
if (retval) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
goto addhost_failed;
}
scsi_scan_host(shost);
return retval;
addhost_failed:
mpi3mr_cleanup_ioc(mrioc);
out_iocinit_failed:
spin_lock(&mrioc_list_lock);
list_del(&mrioc->list);
spin_unlock(&mrioc_list_lock);
scsi_host_put(shost);
shost_failed:
return retval;
}
/**
* mpi3mr_remove - PCI remove callback
* @pdev: PCI device instance
*
* Free up all memory and resources associated with the
* controllerand target devices, unregister the shost.
*
* Return: Nothing.
*/
static void mpi3mr_remove(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct mpi3mr_ioc *mrioc;
mrioc = shost_priv(shost);
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
ssleep(1);
scsi_remove_host(shost);
mpi3mr_cleanup_ioc(mrioc);
spin_lock(&mrioc_list_lock);
list_del(&mrioc->list);
spin_unlock(&mrioc_list_lock);
scsi_host_put(shost);
}
/**
* mpi3mr_shutdown - PCI shutdown callback
* @pdev: PCI device instance
*
* Free up all memory and resources associated with the
* controller
*
* Return: Nothing.
*/
static void mpi3mr_shutdown(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct mpi3mr_ioc *mrioc;
if (!shost)
return;
mrioc = shost_priv(shost);
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
ssleep(1);
mpi3mr_cleanup_ioc(mrioc);
}
static const struct pci_device_id mpi3mr_pci_id_table[] = {
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5,
PCI_ANY_ID, PCI_ANY_ID)
},
{ 0 }
};
MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
static struct pci_driver mpi3mr_pci_driver = {
.name = MPI3MR_DRIVER_NAME,
.id_table = mpi3mr_pci_id_table,
.probe = mpi3mr_probe,
.remove = mpi3mr_remove,
.shutdown = mpi3mr_shutdown,
};
static int __init mpi3mr_init(void)
{
int ret_val;
pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
MPI3MR_DRIVER_VERSION);
ret_val = pci_register_driver(&mpi3mr_pci_driver);
return ret_val;
}
static void __exit mpi3mr_exit(void)
{
if (warn_non_secure_ctlr)
pr_warn(
"Unloading %s version %s while managing a non secure controller\n",
MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION);
else
pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
MPI3MR_DRIVER_VERSION);
pci_unregister_driver(&mpi3mr_pci_driver);
}
module_init(mpi3mr_init);
module_exit(mpi3mr_exit);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment