@@ -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;
+ }
+}
@@ -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 */
@@ -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:
@@ -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,