From: Deepak Ukey <Deepak.Ukey@xxxxxxxxxxxxx> Added the support to register char device for pm80xx module and also added the ioctl functionality to get driver info. Signed-off-by: Deepak Ukey <deepak.ukey@xxxxxxxxxxxxx> Signed-off-by: Viswas G <Viswas.G@xxxxxxxxxxxxx> Signed-off-by: Vishakha Channapattan <vishakhavc@xxxxxxxxxx> Signed-off-by: Bhavesh Jashnani <bjashnani@xxxxxxxxxx> Signed-off-by: Radha Ramachandran <radha@xxxxxxxxxx> Signed-off-by: Akshat Jain <akshatzen@xxxxxxxxxx> Signed-off-by: Yu Zheng <yuuzheng@xxxxxxxxxx> --- drivers/scsi/pm8001/pm8001_ctl.c | 148 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/pm8001/pm8001_ctl.h | 33 +++++++++ drivers/scsi/pm8001/pm8001_init.c | 5 ++ drivers/scsi/pm8001/pm8001_sas.h | 6 ++ 4 files changed, 192 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 7c6be2ec110d..69458b318a20 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -41,6 +41,7 @@ #include <linux/slab.h> #include "pm8001_sas.h" #include "pm8001_ctl.h" +int pm80xx_major = -1; /* scsi host attributes */ @@ -845,3 +846,150 @@ struct device_attribute *pm8001_host_attrs[] = { NULL, }; +/* + * pm8001_open - open the configuration file + * @inode: inode being opened + * @file: file handle attached + * + * Called when the configuration device is opened. Does the needed + * set up on the handle and then returns + * + */ +static int pm8001_open(struct inode *inode, struct file *file) +{ + struct pm8001_hba_info *pm8001_ha; + unsigned int minor_number = iminor(inode); + int err = -ENODEV; + + list_for_each_entry(pm8001_ha, &hba_list, list) { + if (pm8001_ha->id == minor_number) { + file->private_data = pm8001_ha; + err = 0; + break; + } + } + + return err; +} + +/** + * pm8001_close - close the configuration file + * @inode: inode being opened + * @file: file handle attached + * + * Called when the configuration device is closed. Does the needed + * set up on the handle and then returns + * + */ +static int pm8001_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static long pm8001_info_ioctl(struct pm8001_hba_info *pm8001_ha, + unsigned long arg) +{ + u32 ret = 0; + struct ioctl_info_buffer info_buf; + + strcpy(info_buf.information.sz_name, DRV_NAME); + + info_buf.information.usmajor_revision = DRV_MAJOR; + info_buf.information.usminor_revision = DRV_MINOR; + info_buf.information.usbuild_revision = DRV_BUILD; + if (pm8001_ha->chip_id == chip_8001) { + info_buf.information.maxoutstandingIO = + pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io; + info_buf.information.maxdevices = + (pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16) & + 0xFFFF; + } else { + info_buf.information.maxoutstandingIO = + pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io; + info_buf.information.maxdevices = + (pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16) & + 0xFFFF; + } + info_buf.header.return_code = ADPT_IOCTL_CALL_SUCCESS; + + if (copy_to_user((void *)arg, (void *)&info_buf, + sizeof(struct ioctl_info_buffer))) { + ret = ADPT_IOCTL_CALL_FAILED; + } + return ret; +} + +/** + * pm8001_ioctl - pm8001 configuration request + * @inode: inode of device + * @file: file handle + * @cmd: ioctl command code + * @arg: argument + * + * Handles a configuration ioctl. + * + */ +static long pm8001_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + u32 ret = -EACCES; + struct pm8001_hba_info *pm8001_ha; + struct ioctl_header header; + + pm8001_ha = file->private_data; + + switch (cmd) { + case ADPT_IOCTL_INFO: + ret = pm8001_info_ioctl(pm8001_ha, arg); + break; + default: + ret = ADPT_IOCTL_CALL_INVALID_CODE; + } + + if (ret == 0) + return ret; + header.return_code = ret; + ret = -EACCES; + if (copy_to_user((void *)arg, (void *)&header, + sizeof(struct ioctl_header))) { + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("copy_to_user failed\n")); + } + return ret; +} + +static const struct file_operations pm8001_fops = { + .owner = THIS_MODULE, + .open = pm8001_open, + .release = pm8001_close, + .unlocked_ioctl = pm8001_ioctl, +}; + +/** + * pm8001_setup_chrdev - register char device + * Return value: + * 0 in case of success, otherwise non-zero value + */ +int pm8001_setup_chrdev(void) +{ + pm80xx_major = register_chrdev(0, DRV_NAME, &pm8001_fops); + if (pm80xx_major < 0) { + pr_warn("pm8001: unable to register %s device.\n", + DRV_NAME); + return pm80xx_major; + } + return 0; +} + +/** + * pm8001_release_chrdev - unregisters per-adapter management interface + * Return value: + * none + */ +void pm8001_release_chrdev(void) +{ + if (pm80xx_major > -1) { + unregister_chrdev(pm80xx_major, DRV_NAME); + pm80xx_major = -1; + } +} diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h index d0d43a250b9e..f0f8b1deae27 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.h +++ b/drivers/scsi/pm8001/pm8001_ctl.h @@ -59,5 +59,38 @@ #define SYSFS_OFFSET 1024 #define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024) #define PM8001_IB_OB_QUEUE_SIZE (16 * 1024) + +#define ADPT_IOCTL_CALL_SUCCESS 0x00 +#define ADPT_IOCTL_CALL_FAILED 0x01 +#define ADPT_IOCTL_CALL_INVALID_CODE 0x03 + +struct ioctl_header { + u32 io_controller_num; + u32 length; + u32 return_code; + u32 timeout; + u16 direction; +}; + +struct ioctl_drv_info { + u8 sz_name[64]; + u16 usmajor_revision; + u16 usminor_revision; + u16 usbuild_revision; + u16 reserved0; + u32 maxdevices; + u32 maxoutstandingIO; + u32 reserved[16]; +}; + +struct ioctl_info_buffer { + struct ioctl_header header; + struct ioctl_drv_info information; +}; + +#define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *) + +#define ADPT_MAGIC_NUMBER 'm' + #endif /* PM8001_CTL_H_INCLUDED */ diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 775517f9b39d..25e74f1dbd0c 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -1421,6 +1421,9 @@ static int __init pm8001_init(void) pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops); if (!pm8001_stt) goto err_wq; + rc = pm8001_setup_chrdev(); + if (rc) + goto err_ctl; rc = pci_register_driver(&pm8001_pci_driver); if (rc) goto err_tp; @@ -1428,6 +1431,8 @@ static int __init pm8001_init(void) err_tp: sas_release_transport(pm8001_stt); +err_ctl: + pm8001_release_chrdev(); err_wq: destroy_workqueue(pm8001_wq); err: diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 93438c8f67da..479aac34d7cc 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -59,6 +59,9 @@ #define DRV_NAME "pm80xx" #define DRV_VERSION "0.1.39" +#define DRV_MAJOR 1 +#define DRV_MINOR 3 +#define DRV_BUILD 0 #define PM8001_FAIL_LOGGING 0x01 /* Error message logging */ #define PM8001_INIT_LOGGING 0x02 /* driver init logging */ #define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */ @@ -745,6 +748,9 @@ ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf); /* ctl shared API */ extern struct device_attribute *pm8001_host_attrs[]; +int pm8001_setup_chrdev(void); +void pm8001_release_chrdev(void); + static inline void pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha, struct sas_task *task, struct pm8001_ccb_info *ccb, -- 2.16.3