From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jack Wang Subject: Re: [PATCH 11/11] pm80xx : gpio feature support for motherboard controllers Date: Tue, 29 Oct 2013 11:19:01 +0100 Message-ID: <526F8B95.8010900@gmail.com> References: <1382444455-3168-1-git-send-email-Viswas.G@pmcs.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Return-path: Received: from mail-bk0-f46.google.com ([209.85.214.46]:58405 "EHLO mail-bk0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751349Ab3J2KTD (ORCPT ); Tue, 29 Oct 2013 06:19:03 -0400 Received: by mail-bk0-f46.google.com with SMTP id w17so744429bkz.33 for ; Tue, 29 Oct 2013 03:19:01 -0700 (PDT) In-Reply-To: <1382444455-3168-1-git-send-email-Viswas.G@pmcs.com> Sender: linux-scsi-owner@vger.kernel.org List-Id: linux-scsi@vger.kernel.org To: Viswas G Cc: linux-scsi@vger.kernel.org, Sangeetha Gnanasekaran , Nikith Ganigarakoppal , Anand Kumar Santhanam Hi Viswas, As ioctl interface is not welcome for new feature, that's why we removed ioctl interface when pm8001 accepted into mainline. I suggest you use bsg interface for this, see sas_host_smp.c for details. Regards, Jack On 10/22/2013 02:20 PM, Viswas G wrote: > > Signed-off-by: Viswas G > --- > drivers/scsi/pm8001/pm8001_ctl.c | 248 > ++++++++++++++++++++++++++++++++++++- > drivers/scsi/pm8001/pm8001_ctl.h | 55 ++++++++ > drivers/scsi/pm8001/pm8001_init.c | 37 ++++++ > drivers/scsi/pm8001/pm8001_sas.h | 30 +++++ > drivers/scsi/pm8001/pm80xx_hwi.c | 106 ++++++++++++++++ > drivers/scsi/pm8001/pm80xx_hwi.h | 49 +++++++ > 6 files changed, 524 insertions(+), 1 deletions(-) > > diff --git a/drivers/scsi/pm8001/pm8001_ctl.c > b/drivers/scsi/pm8001/pm8001_ctl.c > index 247cb1c..3c9ca21 100644 > --- a/drivers/scsi/pm8001/pm8001_ctl.c > +++ b/drivers/scsi/pm8001/pm8001_ctl.c > @@ -40,7 +40,8 @@ > #include > #include > #include "pm8001_sas.h" > -#include "pm8001_ctl.h" > + > +int pm8001_major = -1; > > /* scsi host attributes */ > > @@ -759,3 +760,248 @@ 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 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; > + union main_cfg_table main_tbl = pm8001_ha->main_cfg_tbl; > + > + 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 = > + main_tbl.pm8001_tbl.max_out_io; > + info_buf.information.maxdevices = > + (main_tbl.pm8001_tbl.max_sgl >> 16) & 0xFFFF; > + } else { > + info_buf.information.maxoutstandingIO = > + main_tbl.pm80xx_tbl.max_out_io; > + info_buf.information.maxdevices = > + (main_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; > +} > + > +static long pm8001_gpio_ioctl(struct pm8001_hba_info *pm8001_ha, > + unsigned long arg) > +{ > + struct gpio_buffer buffer; > + struct pm8001_gpio *payload; > + struct gpio_ioctl_resp *gpio_resp; > + DECLARE_COMPLETION_ONSTACK(completion); > + unsigned long timeout; > + u32 ret = 0, operation; > + > + mutex_lock(&pm8001_ha->ioctl_mutex); > + > + if (copy_from_user(&buffer, (struct gpio_buffer *)arg, > + sizeof(struct gpio_buffer))) { > + ret = ADPT_IOCTL_CALL_FAILED; > + goto exit; > + } > + > + pm8001_ha->ioctl_completion = &completion; > + payload = &buffer.gpio_payload; > + operation = payload->operation; > + ret = PM8001_CHIP_DISP->gpio_req(pm8001_ha, payload); > + if (ret != 0) { > + ret = ADPT_IOCTL_CALL_FAILED; > + goto exit; > + } > + > + timeout = (unsigned long)buffer.header.timeout * 1000; > + > + mod_timer(&pm8001_ha->ioctl_timer, jiffies + > msecs_to_jiffies(timeout)); > + > + wait_for_completion(&completion); > + > + if (pm8001_ha->ioctl_timer_expired) { > + ret = ADPT_IOCTL_CALL_TIMEOUT; > + goto exit; > + } > + gpio_resp = &pm8001_ha->gpio_resp; > + > + buffer.header.return_code = ADPT_IOCTL_CALL_SUCCESS; > + > + if (operation == GPIO_READ) { > + payload->rd_wr_val = gpio_resp->gpio_rd_val; > + payload->input_enable = > gpio_resp->gpio_in_enabled; > + payload->pinsetup1 = gpio_resp->gpio_pinsetup1; > + payload->pinsetup2 = gpio_resp->gpio_pinsetup2; > + payload->event_level = > gpio_resp->gpio_evt_change; > + payload->event_rising_edge = gpio_resp->gpio_evt_rise; > + payload->event_falling_edge = gpio_resp->gpio_evt_fall; > + > + if (copy_to_user((void *)arg, (void *)&buffer, > + sizeof(struct gpio_buffer))) { > + ret = ADPT_IOCTL_CALL_FAILED; > + } > + } else { > + if (copy_to_user((void *)arg, (void *)&buffer.header, > + sizeof(struct ioctl_header))) { > + ret = ADPT_IOCTL_CALL_FAILED; > + } > + } > +exit: > + pm8001_ha->ioctl_timer_expired = 0; > + mutex_unlock(&pm8001_ha->ioctl_mutex); > + 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_GPIO: > + ret = pm8001_gpio_ioctl(pm8001_ha, arg); > + break; > + 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))) { > + return -EFAULT; > + } > + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("IOCTL failed\n")); > + return ret; > +} > + > +/** > + * pm8001_poll - pm8001 poll request function > + * @file: file handle > + * @wait: poll table to wait > + * > + * Handles a poll request. > + * > + */ > +unsigned int pm8001_poll(struct file *file, poll_table *wait) > +{ > + struct pm8001_hba_info *pm8001_ha; > + unsigned int mask = 0; > + > + pm8001_ha = file->private_data; > + > + poll_wait(file, &pm8001_ha->pollq, wait); > + > + if (pm8001_ha->gpio_event_occured == 1) { > + pm8001_ha->gpio_event_occured = 0; > + mask |= POLLIN | POLLRDNORM; > + } > + > + return mask; > +} > + > +static const struct file_operations pm8001_fops = { > + .owner = THIS_MODULE, > + .open = pm8001_open, > + .release = pm8001_close, > + .unlocked_ioctl = pm8001_ioctl, > + .poll = pm8001_poll, > +}; > + > +/** > + * pm8001_setup_chrdev - registers a char device > + * > + * Return value > + * 0 in case of success, otherwise non-zero > + */ > +int pm8001_setup_chrdev(void) > +{ > + pm8001_major = register_chrdev(0, DRV_NAME, &pm8001_fops); > + if (pm8001_major < 0) { > + pr_warn("pm8001 : unable to register \"%s\" device\n", > + DRV_NAME); > + return pm8001_major; > + } > + return 0; > +} > + > +/** > + * pm8001_release_chrdev - unregisters per-adapter management interface > + * > + * Return value > + * none > + */ > +void pm8001_release_chrdev(void) > +{ > + if (pm8001_major > -1) { > + unregister_chrdev(pm8001_major, DRV_NAME); > + pm8001_major = -1; > + } > +} > + > diff --git a/drivers/scsi/pm8001/pm8001_ctl.h > b/drivers/scsi/pm8001/pm8001_ctl.h > index d0d43a2..0064dd3 100644 > --- a/drivers/scsi/pm8001/pm8001_ctl.h > +++ b/drivers/scsi/pm8001/pm8001_ctl.h > @@ -55,6 +55,61 @@ > #define FAIL_OUT_MEMORY 0x000c00 > #define FLASH_IN_PROGRESS 0x001000 > > +#define ADPT_IOCTL_CALL_SUCCESS 0x00 > +#define ADPT_IOCTL_CALL_FAILED 0x01 > +#define ADPT_IOCTL_CALL_INVALID_CODE 0x03 > +#define ADPT_IOCTL_CALL_INVALID_DEVICE 0x04 > +#define ADPT_IOCTL_CALL_TIMEOUT 0x08 > + > +#define GPIO_READ 0 > +#define GPIO_WRITE 1 > +#define GPIO_PINSETUP 2 > +#define GPIO_EVENTSETUP 3 > + > +struct ioctl_header { > + u32 io_controller_num; > + u32 length; > + u32 return_code; > + u32 timeout; > + u32 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 pm8001_gpio { > + u32 operation; > + u32 mask; > + u32 rd_wr_val; > + u32 input_enable; > + u32 pinsetup1; > + u32 pinsetup2; > + u32 event_level; > + u32 event_rising_edge; > + u32 event_falling_edge; > +}; > + > +struct ioctl_info_buffer { > + struct ioctl_header header; > + struct ioctl_drv_info information; > +}; > + > +struct gpio_buffer { > + struct ioctl_header header; > + struct pm8001_gpio gpio_payload; > +}; > + > +#define ADPT_IOCTL_INFO _IOR(0, 0, struct > ioctl_info_buffer *) > +#define ADPT_IOCTL_GPIO _IOWR(0, 1, struct gpio_buffer *) > + > #define IB_OB_READ_TIMES 256 > #define SYSFS_OFFSET 1024 > #define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024) > diff --git a/drivers/scsi/pm8001/pm8001_init.c > b/drivers/scsi/pm8001/pm8001_init.c > index 662bf13..ba2e659 100644 > --- a/drivers/scsi/pm8001/pm8001_init.c > +++ b/drivers/scsi/pm8001/pm8001_init.c > @@ -148,6 +148,8 @@ static void pm8001_free(struct pm8001_hba_info > *pm8001_ha) > if (!pm8001_ha) > return; > > + del_timer(&pm8001_ha->ioctl_timer); > + > for (i = 0; i < USI_MAX_MEMCNT; i++) { > if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { > pci_free_consistent(pm8001_ha->pdev, > @@ -444,6 +446,24 @@ static int pm8001_ioremap(struct pm8001_hba_info > *pm8001_ha) > return 0; > } > > +void pm8001_ioctl_timer_callback(unsigned long data) > +{ > + struct pm8001_hba_info *pm8001_ha = (struct pm8001_hba_info *)data; > + > + PM8001_FAIL_DBG(pm8001_ha, > + pm8001_printk("Timer expired for GPIO response\n")); > + > + spin_lock(&pm8001_ha->ioctl_lock); > + > + if (pm8001_ha->ioctl_completion != NULL) { > + pm8001_ha->ioctl_timer_expired = 1; > + complete(pm8001_ha->ioctl_completion); > + pm8001_ha->ioctl_completion = NULL; > + } > + > + spin_unlock(&pm8001_ha->ioctl_lock); > +} > + > /** > * pm8001_pci_alloc - initialize our ha card structure > * @pdev: pci device. > @@ -479,6 +499,15 @@ static struct pm8001_hba_info > *pm8001_pci_alloc(struct pci_dev *pdev, > else > pm8001_ha->iomb_size = IOMB_SIZE_SPC; > > + mutex_init(&pm8001_ha->ioctl_mutex); > + pm8001_ha->ioctl_completion = NULL; > + init_waitqueue_head(&pm8001_ha->pollq); > + pm8001_ha->gpio_event_occured = 0; > + spin_lock_init(&pm8001_ha->ioctl_lock); > + setup_timer(&pm8001_ha->ioctl_timer, pm8001_ioctl_timer_callback, > + (unsigned long)pm8001_ha); > + > + > #ifdef PM8001_USE_TASKLET > /** > * default tasklet for non msi-x interrupt handler/first msi-x > @@ -1147,8 +1176,15 @@ static int __init pm8001_init(void) > rc = pci_register_driver(&pm8001_pci_driver); > if (rc) > goto err_tp; > + > + rc = pm8001_setup_chrdev(); > + if (rc) > + goto err_ctl; > + > return 0; > > +err_ctl: > + pci_unregister_driver(&pm8001_pci_driver); > err_tp: > sas_release_transport(pm8001_stt); > err_wq: > @@ -1162,6 +1198,7 @@ static void __exit pm8001_exit(void) > pci_unregister_driver(&pm8001_pci_driver); > sas_release_transport(pm8001_stt); > destroy_workqueue(pm8001_wq); > + pm8001_release_chrdev(); > } > > module_init(pm8001_init); > diff --git a/drivers/scsi/pm8001/pm8001_sas.h > b/drivers/scsi/pm8001/pm8001_sas.h > index 9241c04..9171f0a 100644 > --- a/drivers/scsi/pm8001/pm8001_sas.h > +++ b/drivers/scsi/pm8001/pm8001_sas.h > @@ -51,14 +51,21 @@ > #include > #include > #include > +#include > +#include > +#include > #include > #include > #include > #include > #include "pm8001_defs.h" > +#include "pm8001_ctl.h" > > #define DRV_NAME "pm80xx" > #define DRV_VERSION "0.1.37" > +#define DRV_MAJOR 1 > +#define DRV_MINOR 0 > +#define DRV_BUILD 15 > #define PM8001_FAIL_LOGGING 0x01 /* Error message logging */ > #define PM8001_INIT_LOGGING 0x02 /* driver init logging */ > #define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */ > @@ -132,6 +139,17 @@ struct pm8001_ioctl_payload { > u8 *func_specific; > }; > > +struct gpio_ioctl_resp { > + u32 tag; > + u32 gpio_rd_val; > + u32 gpio_in_enabled; > + u32 gpio_pinsetup1; > + u32 gpio_pinsetup2; > + u32 gpio_evt_change; > + u32 gpio_evt_rise; > + u32 gpio_evt_fall; > +}; > + > #define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF > #define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24) > #define MPI_FATAL_EDUMP_TABLE_LO_OFFSET 0x00 /* HNFBUFL */ > @@ -229,6 +247,8 @@ struct pm8001_dispatch { > int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha, > u32 state); > int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha); > + int (*gpio_req)(struct pm8001_hba_info *pm8001_ha, > + struct pm8001_gpio *gpio_payload); > }; > > struct pm8001_chip_info { > @@ -527,6 +547,14 @@ struct pm8001_hba_info { > u32 int_vector; > const struct firmware *fw_image; > u8 outq[PM8001_MAX_MSIX_VEC]; > + struct completion *ioctl_completion; > + struct mutex ioctl_mutex; > + spinlock_t ioctl_lock; > + u32 gpio_event_occured; > + u32 ioctl_timer_expired; > + struct timer_list ioctl_timer; > + struct gpio_ioctl_resp gpio_resp; > + wait_queue_head_t pollq; > }; > > struct pm8001_work { > @@ -705,5 +733,7 @@ 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); > #endif > > diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c > b/drivers/scsi/pm8001/pm80xx_hwi.c > index 4ebc79b..5423844 100644 > --- a/drivers/scsi/pm8001/pm80xx_hwi.c > +++ b/drivers/scsi/pm8001/pm80xx_hwi.c > @@ -3481,6 +3481,54 @@ static int ssp_coalesced_comp_resp(struct > pm8001_hba_info *pm8001_ha, > return 0; > } > > +static int mpi_gpio_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) > +{ > + int ret; > + struct gpio_ioctl_resp *pgpio_resp; > + struct gpio_resp *ppayload = (struct gpio_resp *)(piomb + 4); > + > + spin_lock(&pm8001_ha->ioctl_lock); > + if (pm8001_ha->ioctl_completion != NULL) { > + ret = del_timer(&pm8001_ha->ioctl_timer); > + if (ret) > + PM8001_MSG_DBG(pm8001_ha, > + pm8001_printk("The timer was still in > use.\n")); > + pm8001_ha->ioctl_timer_expired = 0; > + pgpio_resp = &pm8001_ha->gpio_resp; > + pgpio_resp->gpio_rd_val = > le32_to_cpu(ppayload->gpio_rd_val); > + pgpio_resp->gpio_in_enabled = > + le32_to_cpu(ppayload->gpio_in_enabled); > + pgpio_resp->gpio_pinsetup1 = > + le32_to_cpu(ppayload->gpio_pinsetup1); > + pgpio_resp->gpio_pinsetup2 = > + le32_to_cpu(ppayload->gpio_pinsetup2); > + pgpio_resp->gpio_evt_change = > + le32_to_cpu(ppayload->gpio_evt_change); > + pgpio_resp->gpio_evt_rise = > + le32_to_cpu(ppayload->gpio_evt_rise); > + pgpio_resp->gpio_evt_fall = > + le32_to_cpu(ppayload->gpio_evt_fall); > + > + complete(pm8001_ha->ioctl_completion); > + pm8001_ha->ioctl_completion = NULL; > + } > + spin_unlock(&pm8001_ha->ioctl_lock); > + return 0; > +} > + > +static int mpi_gpio_event(struct pm8001_hba_info *pm8001_ha, void *piomb) > +{ > + > + u32 gpio_event = 0; > + struct gpio_event *ppayload = (struct gpio_event *)(piomb + 4); > + gpio_event = le32_to_cpu(ppayload->gpio_event); > + PM8001_MSG_DBG(pm8001_ha, > + pm8001_printk("GPIO event: 0x%X\n", gpio_event)); > + pm8001_ha->gpio_event_occured = 1; > + wake_up_interruptible(&pm8001_ha->pollq); > + return 0; > +} > + > /** > * process_one_iomb - process one outbound Queue memory block > * @pm8001_ha: our hba card information > @@ -3567,10 +3615,12 @@ static void process_one_iomb(struct > pm8001_hba_info *pm8001_ha, void *piomb) > case OPC_OUB_GPIO_RESPONSE: > PM8001_MSG_DBG(pm8001_ha, > pm8001_printk("OPC_OUB_GPIO_RESPONSE\n")); > + mpi_gpio_resp(pm8001_ha, piomb); > break; > case OPC_OUB_GPIO_EVENT: > PM8001_MSG_DBG(pm8001_ha, > pm8001_printk("OPC_OUB_GPIO_EVENT\n")); > + mpi_gpio_event(pm8001_ha, piomb); > break; > case OPC_OUB_GENERAL_EVENT: > PM8001_MSG_DBG(pm8001_ha, > @@ -4510,6 +4560,61 @@ static u32 pm80xx_chip_is_our_interupt(struct > pm8001_hba_info *pm8001_ha) > } > > /** > + * pm80xx_chip_gpio_req - support for GPIO operation > + * @pm8001_ha: our hba card information. > + * @ioctl_payload: the payload for the GPIO operation > + */ > + > +int pm80xx_chip_gpio_req(struct pm8001_hba_info *pm8001_ha, > + struct pm8001_gpio *gpio_payload) > +{ > + struct gpio_req payload; > + struct inbound_queue_table *circularQ; > + int ret; > + u32 tag; > + u32 opc = OPC_INB_GPIO; > + > + if (pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ADAPTEC2) > + return ADPT_IOCTL_CALL_INVALID_DEVICE; > + > + ret = pm8001_tag_alloc(pm8001_ha, &tag); > + if (ret) > + return -1; > + > + memset(&payload, 0, sizeof(payload)); > + circularQ = &pm8001_ha->inbnd_q_tbl[0]; > + payload.tag = cpu_to_le32(tag); > + switch (gpio_payload->operation) { > + case GPIO_READ: > + payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GR_BIT); > + break; > + case GPIO_WRITE: > + payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GW_BIT); > + payload.gpio_wr_msk = cpu_to_le32(gpio_payload->mask); > + payload.gpio_wr_val = cpu_to_le32(gpio_payload->rd_wr_val); > + break; > + case GPIO_PINSETUP: > + payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GS_BIT); > + payload.gpio_in_enabled = > + cpu_to_le32(gpio_payload->input_enable); > + payload.gpio_pinsetup1 = > cpu_to_le32(gpio_payload->pinsetup1); > + payload.gpio_pinsetup2 = > cpu_to_le32(gpio_payload->pinsetup2); > + break; > + case GPIO_EVENTSETUP: > + payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GE_BIT); > + payload.gpio_evt_change = > + cpu_to_le32(gpio_payload->event_level); > + payload.gpio_evt_rise = > + cpu_to_le32(gpio_payload->event_rising_edge); > + payload.gpio_evt_fall = > + cpu_to_le32(gpio_payload->event_falling_edge); > + break; > + } > + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); > + return ret; > +} > + > +/** > * pm8001_chip_isr - PM8001 isr handler. > * @pm8001_ha: our hba card information. > * @irq: irq number. > @@ -4589,4 +4694,5 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = { > .set_nvmd_req = pm8001_chip_set_nvmd_req, > .fw_flash_update_req = pm8001_chip_fw_flash_update_req, > .set_dev_state_req = pm8001_chip_set_dev_state_req, > + .gpio_req = pm80xx_chip_gpio_req, > }; > diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h > b/drivers/scsi/pm8001/pm80xx_hwi.h > index c86816b..671940a 100644 > --- a/drivers/scsi/pm8001/pm80xx_hwi.h > +++ b/drivers/scsi/pm8001/pm80xx_hwi.h > @@ -422,6 +422,55 @@ struct hw_event_ack_req { > } __attribute__((packed, aligned(4))); > > /* > + * brief the data structure of GPIO Commannd > + * use to control MPI GPIOs (64 bytes) > + */ > +struct gpio_req { > + __le32 tag; > + __le32 eobid_ge_gs_gr_gw; > + __le32 gpio_wr_msk; > + __le32 gpio_wr_val; > + __le32 gpio_in_enabled; > + __le32 gpio_pinsetup1; > + __le32 gpio_pinsetup2; > + __le32 gpio_evt_change; > + __le32 gpio_evt_rise; > + __le32 gpio_evt_fall; > + u32 reserved[5]; > +} __attribute__((packed, aligned(4))); > + > +#define GPIO_GW_BIT 0x1 > +#define GPIO_GR_BIT 0x2 > +#define GPIO_GS_BIT 0x4 > +#define GPIO_GE_BIT 0x8 > + > +/* > + * brief the data structure of GPIO Response > + * indicates the completion of GPIO command (64 bytes) > + */ > +struct gpio_resp { > + __le32 tag; > + u32 reserved[2]; > + __le32 gpio_rd_val; > + __le32 gpio_in_enabled; > + __le32 gpio_pinsetup1; > + __le32 gpio_pinsetup2; > + __le32 gpio_evt_change; > + __le32 gpio_evt_rise; > + __le32 gpio_evt_fall; > + u32 reserved1[5]; > +} __attribute__((packed, aligned(4))); > + > +/* > + * brief the data structure of GPIO Event > + * indicates the generation of GPIO event (64 bytes) > + */ > +struct gpio_event { > + __le32 gpio_event; > + u32 reserved[14]; > +} __attribute__((packed, aligned(4))); > + > +/* > * brief the data structure of PHY_START Response Command > * indicates the completion of PHY_START command (64 bytes) > */ > -- > 1.7.1 >