From: Tomas Henzl <thenzl@redhat.com>
To: Ching Huang <ching2048@areca.com.tw>,
hch@infradead.org, jbottomley@parallels.com,
dan.carpenter@oracle.com, agordeev@redhat.com,
linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 13/17] arcmsr: fix ioctl data read/write error for adapter type C
Date: Fri, 22 Aug 2014 18:00:13 +0200 [thread overview]
Message-ID: <53F7690D.5070007@redhat.com> (raw)
In-Reply-To: <1408432665.4748.65.camel@Centos6.3-64>
On 08/19/2014 09:17 AM, Ching Huang wrote:
> From: Ching Huang <ching2048@areca.com.tw>
>
> Rewrite ioctl entry and its relate function.
> This patch fix ioctl data read/write error and change data I/O access from byte to Dword.
>
> Signed-off-by: Ching Huang <ching2048@areca.com.tw>
> ---
>
> diff -uprN a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
> --- a/drivers/scsi/arcmsr/arcmsr_attr.c 2014-02-06 17:47:24.000000000 +0800
> +++ b/drivers/scsi/arcmsr/arcmsr_attr.c 2014-04-29 17:10:42.000000000 +0800
> @@ -70,40 +70,75 @@ static ssize_t arcmsr_sysfs_iop_message_
> struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
> uint8_t *pQbuffer,*ptmpQbuffer;
> int32_t allxfer_len = 0;
> + unsigned long flags;
>
> if (!capable(CAP_SYS_ADMIN))
> return -EACCES;
>
> /* do message unit read. */
> ptmpQbuffer = (uint8_t *)buf;
> - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
> - && (allxfer_len < 1031)) {
> + spin_lock_irqsave(&acb->rqbuffer_lock, flags);
> + if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
Hi - does this condition (acb->rqbuf_firstindex == acb->rqbuf_lastindex) mean we could just release
the spinlock and return ?
> pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
> - memcpy(ptmpQbuffer, pQbuffer, 1);
> - acb->rqbuf_firstindex++;
> - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
> - ptmpQbuffer++;
> - allxfer_len++;
> + if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) {
> + if ((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex) >= 1032) {
> + memcpy(ptmpQbuffer, pQbuffer, 1032);
> + acb->rqbuf_firstindex += 1032;
> + acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
> + allxfer_len = 1032;
> + } else {
> + if (((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex)
> + + acb->rqbuf_lastindex) > 1032) {
> + memcpy(ptmpQbuffer, pQbuffer,
> + ARCMSR_MAX_QBUFFER
> + - acb->rqbuf_firstindex);
> + ptmpQbuffer += ARCMSR_MAX_QBUFFER
> + - acb->rqbuf_firstindex;
> + memcpy(ptmpQbuffer, acb->rqbuffer, 1032
> + - (ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex));
This code looks like you were copying some data from a ring buffer,
in that case - shouldn't be acb->rqbuf_lastindex used instead of firstindex?
What does the 1032 mean is that a hw. limit, actually could you explain the code
should do? Maybe I'm just wrong with my assumptions.
Thanks,
Tomas
> + acb->rqbuf_firstindex = 1032 -
> + (ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex);
> + allxfer_len = 1032;
> + } else {
> + memcpy(ptmpQbuffer, pQbuffer,
> + ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex);
> + ptmpQbuffer += ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex;
> + memcpy(ptmpQbuffer, acb->rqbuffer,
> + acb->rqbuf_lastindex);
> + allxfer_len = ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex +
> + acb->rqbuf_lastindex;
> + acb->rqbuf_firstindex =
> + acb->rqbuf_lastindex;
> + }
> + }
> + } else {
> + if ((acb->rqbuf_lastindex - acb->rqbuf_firstindex) > 1032) {
> + memcpy(ptmpQbuffer, pQbuffer, 1032);
> + acb->rqbuf_firstindex += 1032;
> + allxfer_len = 1032;
> + } else {
> + memcpy(ptmpQbuffer, pQbuffer, acb->rqbuf_lastindex
> + - acb->rqbuf_firstindex);
> + allxfer_len = acb->rqbuf_lastindex -
> + acb->rqbuf_firstindex;
> + acb->rqbuf_firstindex = acb->rqbuf_lastindex;
> + }
> + }
> }
> if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> struct QBUFFER __iomem *prbuffer;
> - uint8_t __iomem *iop_data;
> - int32_t iop_len;
> -
> acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
> prbuffer = arcmsr_get_iop_rqbuffer(acb);
> - iop_data = prbuffer->data;
> - iop_len = readl(&prbuffer->data_len);
> - while (iop_len > 0) {
> - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
> - acb->rqbuf_lastindex++;
> - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
> - iop_data++;
> - iop_len--;
> - }
> - arcmsr_iop_message_read(acb);
> + if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
> + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
> }
> - return (allxfer_len);
> + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
> + return allxfer_len;
> }
>
> static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp,
> @@ -117,6 +152,7 @@ static ssize_t arcmsr_sysfs_iop_message_
> struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
> int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
> uint8_t *pQbuffer, *ptmpuserbuffer;
> + unsigned long flags;
>
> if (!capable(CAP_SYS_ADMIN))
> return -EACCES;
> @@ -125,18 +161,19 @@ static ssize_t arcmsr_sysfs_iop_message_
> /* do message unit write. */
> ptmpuserbuffer = (uint8_t *)buf;
> user_len = (int32_t)count;
> + spin_lock_irqsave(&acb->wqbuffer_lock, flags);
> wqbuf_lastindex = acb->wqbuf_lastindex;
> wqbuf_firstindex = acb->wqbuf_firstindex;
> if (wqbuf_lastindex != wqbuf_firstindex) {
> - arcmsr_post_ioctldata2iop(acb);
> + arcmsr_write_ioctldata2iop(acb);
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> return 0; /*need retry*/
> } else {
> my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
> - &(ARCMSR_MAX_QBUFFER - 1);
> + &(ARCMSR_MAX_QBUFFER - 1);
> if (my_empty_len >= user_len) {
> while (user_len > 0) {
> - pQbuffer =
> - &acb->wqbuffer[acb->wqbuf_lastindex];
> + pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex];
> memcpy(pQbuffer, ptmpuserbuffer, 1);
> acb->wqbuf_lastindex++;
> acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
> @@ -146,10 +183,12 @@ static ssize_t arcmsr_sysfs_iop_message_
> if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
> acb->acb_flags &=
> ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
> - arcmsr_post_ioctldata2iop(acb);
> + arcmsr_write_ioctldata2iop(acb);
> }
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> return count;
> } else {
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> return 0; /*need retry*/
> }
> }
> @@ -165,22 +204,24 @@ static ssize_t arcmsr_sysfs_iop_message_
> struct Scsi_Host *host = class_to_shost(dev);
> struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
> uint8_t *pQbuffer;
> + unsigned long flags;
>
> if (!capable(CAP_SYS_ADMIN))
> return -EACCES;
>
> - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
> - arcmsr_iop_message_read(acb);
> - }
> + arcmsr_clear_iop2drv_rqueue_buffer(acb);
> acb->acb_flags |=
> (ACB_F_MESSAGE_WQBUFFER_CLEARED
> | ACB_F_MESSAGE_RQBUFFER_CLEARED
> | ACB_F_MESSAGE_WQBUFFER_READED);
> + spin_lock_irqsave(&acb->rqbuffer_lock, flags);
> acb->rqbuf_firstindex = 0;
> acb->rqbuf_lastindex = 0;
> + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
> + spin_lock_irqsave(&acb->wqbuffer_lock, flags);
> acb->wqbuf_firstindex = 0;
> acb->wqbuf_lastindex = 0;
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> pQbuffer = acb->rqbuffer;
> memset(pQbuffer, 0, sizeof (struct QBUFFER));
> pQbuffer = acb->wqbuffer;
> diff -uprN a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
> --- a/drivers/scsi/arcmsr/arcmsr.h 2014-05-06 15:28:38.000000000 +0800
> +++ b/drivers/scsi/arcmsr/arcmsr.h 2014-05-06 15:28:58.000000000 +0800
> @@ -518,6 +518,8 @@ struct AdapterControlBlock
> uint32_t reg_mu_acc_handle0;
> spinlock_t eh_lock;
> spinlock_t ccblist_lock;
> + spinlock_t rqbuffer_lock;
> + spinlock_t wqbuffer_lock;
> union {
> struct MessageUnit_A __iomem *pmuA;
> struct MessageUnit_B *pmuB;
> @@ -693,8 +695,10 @@ struct SENSE_DATA
> #define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01
> #define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F
>
> -extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *);
> -extern void arcmsr_iop_message_read(struct AdapterControlBlock *);
> +extern void arcmsr_write_ioctldata2iop(struct AdapterControlBlock *);
> +extern uint32_t arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *,
> + struct QBUFFER __iomem *);
> +extern void arcmsr_clear_iop2drv_rqueue_buffer(struct AdapterControlBlock *);
> extern struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *);
> extern struct device_attribute *arcmsr_host_attrs[];
> extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *);
> diff -uprN a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
> --- a/drivers/scsi/arcmsr/arcmsr_hba.c 2014-08-14 18:40:38.000000000 +0800
> +++ b/drivers/scsi/arcmsr/arcmsr_hba.c 2014-08-14 18:40:48.000000000 +0800
> @@ -627,6 +627,8 @@ static int arcmsr_probe(struct pci_dev *
> }
> spin_lock_init(&acb->eh_lock);
> spin_lock_init(&acb->ccblist_lock);
> + spin_lock_init(&acb->rqbuffer_lock);
> + spin_lock_init(&acb->wqbuffer_lock);
> acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
> ACB_F_MESSAGE_RQBUFFER_CLEARED |
> ACB_F_MESSAGE_WQBUFFER_READED);
> @@ -1423,68 +1425,174 @@ static struct QBUFFER __iomem *arcmsr_ge
> return pqbuffer;
> }
>
> -static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
> -{
> - struct QBUFFER __iomem *prbuffer;
> - struct QBUFFER *pQbuffer;
> - uint8_t __iomem *iop_data;
> - int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
> - rqbuf_lastindex = acb->rqbuf_lastindex;
> - rqbuf_firstindex = acb->rqbuf_firstindex;
> - prbuffer = arcmsr_get_iop_rqbuffer(acb);
> - iop_data = (uint8_t __iomem *)prbuffer->data;
> - iop_len = prbuffer->data_len;
> - my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1);
> +static uint32_t arcmsr_Read_iop_rqbuffer_in_DWORD(struct AdapterControlBlock *acb,
> + struct QBUFFER __iomem *prbuffer) {
>
> - if (my_empty_len >= iop_len)
> - {
> - while (iop_len > 0) {
> - pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
> - memcpy(pQbuffer, iop_data, 1);
> - rqbuf_lastindex++;
> - rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
> + uint8_t *pQbuffer;
> + uint8_t *buf1 = NULL;
> + uint32_t __iomem *iop_data;
> + uint32_t iop_len, data_len, *buf2 = NULL;
> +
> + iop_data = (uint32_t __iomem *)prbuffer->data;
> + iop_len = readl(&prbuffer->data_len);
> + if (iop_len > 0) {
> + buf1 = kmalloc(128, GFP_ATOMIC);
> + buf2 = (uint32_t *)buf1;
> + if (buf1 == NULL)
> + return 0;
> + data_len = iop_len;
> + while (data_len >= 4) {
> + *buf2++ = readl(iop_data);
> iop_data++;
> - iop_len--;
> + data_len -= 4;
> }
> - acb->rqbuf_lastindex = rqbuf_lastindex;
> - arcmsr_iop_message_read(acb);
> + if (data_len)
> + *buf2 = readl(iop_data);
> + buf2 = (uint32_t *)buf1;
> + }
> + while (iop_len > 0) {
> + pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
> + *pQbuffer = *buf1;
> + acb->rqbuf_lastindex++;
> + /* if last, index number set it to 0 */
> + acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
> + buf1++;
> + iop_len--;
> + }
> + if (buf2)
This test is not needed.
> + kfree(buf2);
> + /* let IOP know data has been read */
> + arcmsr_iop_message_read(acb);
> + return 1;
> +}
> +
> +uint32_t
> +arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb,
> + struct QBUFFER __iomem *prbuffer) {
> +
> + uint8_t *pQbuffer;
> + uint8_t __iomem *iop_data;
> + uint32_t iop_len;
> +
> + if (acb->adapter_type & ACB_ADAPTER_TYPE_C)
> + return arcmsr_Read_iop_rqbuffer_in_DWORD(acb, prbuffer);
> + iop_data = (uint8_t __iomem *)prbuffer->data;
> + iop_len = readl(&prbuffer->data_len);
> + while (iop_len > 0) {
> + pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
> + *pQbuffer = readb(iop_data);
> + acb->rqbuf_lastindex++;
> + acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
> + iop_data++;
> + iop_len--;
> }
> + arcmsr_iop_message_read(acb);
> + return 1;
> +}
> +
> +static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
> +{
> + unsigned long flags;
> + struct QBUFFER __iomem *prbuffer;
> + int32_t buf_empty_len;
>
> - else {
> + spin_lock_irqsave(&acb->rqbuffer_lock, flags);
> + prbuffer = arcmsr_get_iop_rqbuffer(acb);
> + buf_empty_len = (acb->rqbuf_lastindex - acb->rqbuf_firstindex - 1) &
> + (ARCMSR_MAX_QBUFFER - 1);
> + if (buf_empty_len >= readl(&prbuffer->data_len)) {
> + if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
> + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
> + } else
> acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
> + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
> +}
> +
> +static void arcmsr_write_ioctldata2iop_in_DWORD(struct AdapterControlBlock *acb)
> +{
> + uint8_t *pQbuffer;
> + struct QBUFFER __iomem *pwbuffer;
> + uint8_t *buf1 = NULL;
> + uint32_t __iomem *iop_data;
> + uint32_t allxfer_len = 0, data_len, *buf2 = NULL, data;
> +
> + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
> + buf1 = kmalloc(128, GFP_ATOMIC);
> + buf2 = (uint32_t *)buf1;
> + if (buf1 == NULL)
> + return;
> +
> + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
> + pwbuffer = arcmsr_get_iop_wqbuffer(acb);
> + iop_data = (uint32_t __iomem *)pwbuffer->data;
> + while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
> + && (allxfer_len < 124)) {
> + pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
> + *buf1 = *pQbuffer;
> + acb->wqbuf_firstindex++;
> + acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
> + buf1++;
> + allxfer_len++;
> + }
> + data_len = allxfer_len;
> + buf1 = (uint8_t *)buf2;
> + while (data_len >= 4) {
> + data = *buf2++;
> + writel(data, iop_data);
> + iop_data++;
> + data_len -= 4;
> + }
> + if (data_len) {
> + data = *buf2;
> + writel(data, iop_data);
> + }
> + writel(allxfer_len, &pwbuffer->data_len);
> + kfree(buf1);
> + arcmsr_iop_message_wrote(acb);
> }
> }
>
> -static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
> +void
> +arcmsr_write_ioctldata2iop(struct AdapterControlBlock *acb)
> {
> - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
> - if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
> - uint8_t *pQbuffer;
> - struct QBUFFER __iomem *pwbuffer;
> - uint8_t __iomem *iop_data;
> - int32_t allxfer_len = 0;
> + uint8_t *pQbuffer;
> + struct QBUFFER __iomem *pwbuffer;
> + uint8_t __iomem *iop_data;
> + int32_t allxfer_len = 0;
>
> + if (acb->adapter_type & ACB_ADAPTER_TYPE_C) {
> + arcmsr_write_ioctldata2iop_in_DWORD(acb);
> + return;
> + }
> + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
> acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
> pwbuffer = arcmsr_get_iop_wqbuffer(acb);
> iop_data = (uint8_t __iomem *)pwbuffer->data;
> -
> - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \
> - (allxfer_len < 124)) {
> + while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
> + && (allxfer_len < 124)) {
> pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
> - memcpy(iop_data, pQbuffer, 1);
> + writeb(*pQbuffer, iop_data);
> acb->wqbuf_firstindex++;
> acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
> iop_data++;
> allxfer_len++;
> }
> - pwbuffer->data_len = allxfer_len;
> -
> + writel(allxfer_len, &pwbuffer->data_len);
> arcmsr_iop_message_wrote(acb);
> }
> +}
>
> - if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) {
> +static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&acb->wqbuffer_lock, flags);
> + acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
> + if (acb->wqbuf_firstindex != acb->wqbuf_lastindex)
> + arcmsr_write_ioctldata2iop(acb);
> + if (acb->wqbuf_firstindex == acb->wqbuf_lastindex)
> acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
> - }
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> }
>
> static void arcmsr_hbaA_doorbell_isr(struct AdapterControlBlock *acb)
> @@ -1742,296 +1850,344 @@ static void arcmsr_iop_parking(struct Ad
> }
> }
>
> -void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
> +
> +void arcmsr_clear_iop2drv_rqueue_buffer(struct AdapterControlBlock *acb)
> {
> - int32_t wqbuf_firstindex, wqbuf_lastindex;
> - uint8_t *pQbuffer;
> - struct QBUFFER __iomem *pwbuffer;
> - uint8_t __iomem *iop_data;
> - int32_t allxfer_len = 0;
> - pwbuffer = arcmsr_get_iop_wqbuffer(acb);
> - iop_data = (uint8_t __iomem *)pwbuffer->data;
> - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
> - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
> - wqbuf_firstindex = acb->wqbuf_firstindex;
> - wqbuf_lastindex = acb->wqbuf_lastindex;
> - while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) {
> - pQbuffer = &acb->wqbuffer[wqbuf_firstindex];
> - memcpy(iop_data, pQbuffer, 1);
> - wqbuf_firstindex++;
> - wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
> - iop_data++;
> - allxfer_len++;
> + uint32_t i;
> +
> + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> + for (i = 0; i < 15; i++) {
> + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
> + acb->rqbuf_firstindex = 0;
> + acb->rqbuf_lastindex = 0;
> + arcmsr_iop_message_read(acb);
> + mdelay(30);
> + } else if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
> + acb->rqbuf_firstindex = 0;
> + acb->rqbuf_lastindex = 0;
> + mdelay(30);
> + } else
> + break;
> }
> - acb->wqbuf_firstindex = wqbuf_firstindex;
> - pwbuffer->data_len = allxfer_len;
> - arcmsr_iop_message_wrote(acb);
> }
> }
>
> -static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
> - struct scsi_cmnd *cmd)
> +static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd)
> {
> - struct CMD_MESSAGE_FIELD *pcmdmessagefld;
> - int retvalue = 0, transfer_len = 0;
> char *buffer;
> + unsigned short use_sg;
> + int retvalue = 0, transfer_len = 0;
> + unsigned long flags;
> + struct CMD_MESSAGE_FIELD *pcmdmessagefld;
> + uint32_t controlcode = (uint32_t)cmd->cmnd[5] << 24 |
> + (uint32_t)cmd->cmnd[6] << 16 |
> + (uint32_t)cmd->cmnd[7] << 8 |
> + (uint32_t)cmd->cmnd[8];
> struct scatterlist *sg;
> - uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
> - (uint32_t ) cmd->cmnd[6] << 16 |
> - (uint32_t ) cmd->cmnd[7] << 8 |
> - (uint32_t ) cmd->cmnd[8];
> - /* 4 bytes: Areca io control code */
> +
> + use_sg = scsi_sg_count(cmd);
> sg = scsi_sglist(cmd);
> buffer = kmap_atomic(sg_page(sg)) + sg->offset;
> - if (scsi_sg_count(cmd) > 1) {
> + if (use_sg > 1) {
> retvalue = ARCMSR_MESSAGE_FAIL;
> goto message_out;
> }
> transfer_len += sg->length;
> -
> if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
> retvalue = ARCMSR_MESSAGE_FAIL;
> + pr_info("%s: ARCMSR_MESSAGE_FAIL!\n", __func__);
> goto message_out;
> }
> - pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
> - switch(controlcode) {
> -
> + pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)buffer;
> + switch (controlcode) {
> case ARCMSR_MESSAGE_READ_RQBUFFER: {
> unsigned char *ver_addr;
> uint8_t *pQbuffer, *ptmpQbuffer;
> - int32_t allxfer_len = 0;
> -
> + uint32_t allxfer_len = 0;
> ver_addr = kmalloc(1032, GFP_ATOMIC);
> if (!ver_addr) {
> retvalue = ARCMSR_MESSAGE_FAIL;
> + pr_info("%s: memory not enough!\n", __func__);
> goto message_out;
> }
> -
> ptmpQbuffer = ver_addr;
> - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
> - && (allxfer_len < 1031)) {
> + spin_lock_irqsave(&acb->rqbuffer_lock, flags);
> + if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
> pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
> - memcpy(ptmpQbuffer, pQbuffer, 1);
> - acb->rqbuf_firstindex++;
> - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
> - ptmpQbuffer++;
> - allxfer_len++;
> + if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) {
> + if ((ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex) >= 1032) {
> + memcpy(ptmpQbuffer, pQbuffer, 1032);
> + acb->rqbuf_firstindex += 1032;
> + acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
> + allxfer_len = 1032;
> + } else {
> + if (((ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex) +
> + acb->rqbuf_lastindex) > 1032) {
> + memcpy(ptmpQbuffer,
> + pQbuffer, ARCMSR_MAX_QBUFFER
> + - acb->rqbuf_firstindex);
> + ptmpQbuffer +=
> + ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex;
> + memcpy(ptmpQbuffer,
> + acb->rqbuffer, 1032 -
> + (ARCMSR_MAX_QBUFFER
> + - acb->rqbuf_firstindex));
> + acb->rqbuf_firstindex =
> + 1032 - (ARCMSR_MAX_QBUFFER
> + - acb->rqbuf_firstindex);
> + allxfer_len = 1032;
> + } else {
> + memcpy(ptmpQbuffer,
> + pQbuffer, ARCMSR_MAX_QBUFFER
> + - acb->rqbuf_firstindex);
> + ptmpQbuffer +=
> + ARCMSR_MAX_QBUFFER -
> + acb->rqbuf_firstindex;
> + memcpy(ptmpQbuffer,
> + acb->rqbuffer,
> + acb->rqbuf_lastindex);
> + allxfer_len = ARCMSR_MAX_QBUFFER
> + - acb->rqbuf_firstindex +
> + acb->rqbuf_lastindex;
> + acb->rqbuf_firstindex =
> + acb->rqbuf_lastindex;
> + }
> + }
> + } else {
> + if ((acb->rqbuf_lastindex -
> + acb->rqbuf_firstindex) > 1032) {
> + memcpy(ptmpQbuffer, pQbuffer, 1032);
> + acb->rqbuf_firstindex += 1032;
> + allxfer_len = 1032;
> + } else {
> + memcpy(ptmpQbuffer, pQbuffer,
> + acb->rqbuf_lastindex -
> + acb->rqbuf_firstindex);
> + allxfer_len = acb->rqbuf_lastindex
> + - acb->rqbuf_firstindex;
> + acb->rqbuf_firstindex =
> + acb->rqbuf_lastindex;
> + }
> + }
> }
> + memcpy(pcmdmessagefld->messagedatabuffer, ver_addr,
> + allxfer_len);
> if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> -
> struct QBUFFER __iomem *prbuffer;
> - uint8_t __iomem *iop_data;
> - int32_t iop_len;
> -
> acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
> prbuffer = arcmsr_get_iop_rqbuffer(acb);
> - iop_data = prbuffer->data;
> - iop_len = readl(&prbuffer->data_len);
> - while (iop_len > 0) {
> - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
> - acb->rqbuf_lastindex++;
> - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
> - iop_data++;
> - iop_len--;
> - }
> - arcmsr_iop_message_read(acb);
> - }
> - memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
> - pcmdmessagefld->cmdmessage.Length = allxfer_len;
> - if(acb->fw_flag == FW_DEADLOCK) {
> - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }else{
> - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
> + if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
> + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
> }
> + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
> kfree(ver_addr);
> - }
> + pcmdmessagefld->cmdmessage.Length = allxfer_len;
> + if (acb->fw_flag == FW_DEADLOCK)
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> break;
> -
> + }
> case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
> unsigned char *ver_addr;
> int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
> uint8_t *pQbuffer, *ptmpuserbuffer;
> -
> ver_addr = kmalloc(1032, GFP_ATOMIC);
> if (!ver_addr) {
> retvalue = ARCMSR_MESSAGE_FAIL;
> goto message_out;
> }
> - if(acb->fw_flag == FW_DEADLOCK) {
> - pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }else{
> - pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_OK;
> - }
> ptmpuserbuffer = ver_addr;
> user_len = pcmdmessagefld->cmdmessage.Length;
> - memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
> + memcpy(ptmpuserbuffer,
> + pcmdmessagefld->messagedatabuffer, user_len);
> + spin_lock_irqsave(&acb->wqbuffer_lock, flags);
> wqbuf_lastindex = acb->wqbuf_lastindex;
> wqbuf_firstindex = acb->wqbuf_firstindex;
> if (wqbuf_lastindex != wqbuf_firstindex) {
> struct SENSE_DATA *sensebuffer =
> (struct SENSE_DATA *)cmd->sense_buffer;
> - arcmsr_post_ioctldata2iop(acb);
> + arcmsr_write_ioctldata2iop(acb);
> /* has error report sensedata */
> - sensebuffer->ErrorCode = 0x70;
> + sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
> sensebuffer->SenseKey = ILLEGAL_REQUEST;
> sensebuffer->AdditionalSenseLength = 0x0A;
> sensebuffer->AdditionalSenseCode = 0x20;
> sensebuffer->Valid = 1;
> retvalue = ARCMSR_MESSAGE_FAIL;
> } else {
> - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
> - &(ARCMSR_MAX_QBUFFER - 1);
> + my_empty_len = (wqbuf_firstindex - wqbuf_lastindex - 1)
> + & (ARCMSR_MAX_QBUFFER - 1);
> if (my_empty_len >= user_len) {
> while (user_len > 0) {
> - pQbuffer =
> - &acb->wqbuffer[acb->wqbuf_lastindex];
> - memcpy(pQbuffer, ptmpuserbuffer, 1);
> - acb->wqbuf_lastindex++;
> - acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
> - ptmpuserbuffer++;
> - user_len--;
> + pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex];
> + if ((acb->wqbuf_lastindex + user_len)
> + > ARCMSR_MAX_QBUFFER) {
> + memcpy(pQbuffer, ptmpuserbuffer,
> + ARCMSR_MAX_QBUFFER -
> + acb->wqbuf_lastindex);
> + ptmpuserbuffer +=
> + (ARCMSR_MAX_QBUFFER
> + - acb->wqbuf_lastindex);
> + user_len -= (ARCMSR_MAX_QBUFFER
> + - acb->wqbuf_lastindex);
> + acb->wqbuf_lastindex = 0;
> + } else {
> + memcpy(pQbuffer, ptmpuserbuffer,
> + user_len);
> + acb->wqbuf_lastindex += user_len;
> + acb->wqbuf_lastindex %=
> + ARCMSR_MAX_QBUFFER;
> + user_len = 0;
> + }
> }
> - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
> + if (acb->acb_flags &
> + ACB_F_MESSAGE_WQBUFFER_CLEARED) {
> acb->acb_flags &=
> ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
> - arcmsr_post_ioctldata2iop(acb);
> + arcmsr_write_ioctldata2iop(acb);
> }
> } else {
> - /* has error report sensedata */
> struct SENSE_DATA *sensebuffer =
> (struct SENSE_DATA *)cmd->sense_buffer;
> - sensebuffer->ErrorCode = 0x70;
> + /* has error report sensedata */
> + sensebuffer->ErrorCode =
> + SCSI_SENSE_CURRENT_ERRORS;
> sensebuffer->SenseKey = ILLEGAL_REQUEST;
> sensebuffer->AdditionalSenseLength = 0x0A;
> sensebuffer->AdditionalSenseCode = 0x20;
> sensebuffer->Valid = 1;
> retvalue = ARCMSR_MESSAGE_FAIL;
> }
> - }
> - kfree(ver_addr);
> }
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> + kfree(ver_addr);
> + if (acb->fw_flag == FW_DEADLOCK)
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> break;
> -
> + }
> case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
> uint8_t *pQbuffer = acb->rqbuffer;
> - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
> - arcmsr_iop_message_read(acb);
> - }
> +
> + arcmsr_clear_iop2drv_rqueue_buffer(acb);
> + spin_lock_irqsave(&acb->rqbuffer_lock, flags);
> acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
> acb->rqbuf_firstindex = 0;
> acb->rqbuf_lastindex = 0;
> memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
> - if(acb->fw_flag == FW_DEADLOCK) {
> + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
> + if (acb->fw_flag == FW_DEADLOCK)
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }else{
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_OK;
> - }
> - }
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> break;
> -
> + }
> case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
> uint8_t *pQbuffer = acb->wqbuffer;
> - if(acb->fw_flag == FW_DEADLOCK) {
> - pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }else{
> - pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_OK;
> - }
> -
> - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
> - arcmsr_iop_message_read(acb);
> - }
> - acb->acb_flags |=
> - (ACB_F_MESSAGE_WQBUFFER_CLEARED |
> - ACB_F_MESSAGE_WQBUFFER_READED);
> + spin_lock_irqsave(&acb->wqbuffer_lock, flags);
> + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
> + ACB_F_MESSAGE_WQBUFFER_READED);
> acb->wqbuf_firstindex = 0;
> acb->wqbuf_lastindex = 0;
> memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
> - }
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> + if (acb->fw_flag == FW_DEADLOCK)
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> break;
> -
> + }
> case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
> uint8_t *pQbuffer;
> -
> - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
> - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
> - arcmsr_iop_message_read(acb);
> - }
> - acb->acb_flags |=
> - (ACB_F_MESSAGE_WQBUFFER_CLEARED
> - | ACB_F_MESSAGE_RQBUFFER_CLEARED
> - | ACB_F_MESSAGE_WQBUFFER_READED);
> + arcmsr_clear_iop2drv_rqueue_buffer(acb);
> + spin_lock_irqsave(&acb->rqbuffer_lock, flags);
> + acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
> acb->rqbuf_firstindex = 0;
> acb->rqbuf_lastindex = 0;
> - acb->wqbuf_firstindex = 0;
> - acb->wqbuf_lastindex = 0;
> pQbuffer = acb->rqbuffer;
> memset(pQbuffer, 0, sizeof(struct QBUFFER));
> + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
> + spin_lock_irqsave(&acb->wqbuffer_lock, flags);
> + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
> + ACB_F_MESSAGE_WQBUFFER_READED);
> + acb->wqbuf_firstindex = 0;
> + acb->wqbuf_lastindex = 0;
> pQbuffer = acb->wqbuffer;
> memset(pQbuffer, 0, sizeof(struct QBUFFER));
> - if(acb->fw_flag == FW_DEADLOCK) {
> + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
> + if (acb->fw_flag == FW_DEADLOCK)
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }else{
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_OK;
> - }
> - }
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> break;
> -
> + }
> case ARCMSR_MESSAGE_RETURN_CODE_3F: {
> - if(acb->fw_flag == FW_DEADLOCK) {
> + if (acb->fw_flag == FW_DEADLOCK)
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }else{
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_3F;
> - }
> + ARCMSR_MESSAGE_RETURNCODE_3F;
> break;
> - }
> + }
> case ARCMSR_MESSAGE_SAY_HELLO: {
> int8_t *hello_string = "Hello! I am ARCMSR";
> - if(acb->fw_flag == FW_DEADLOCK) {
> + if (acb->fw_flag == FW_DEADLOCK)
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }else{
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_OK;
> - }
> - memcpy(pcmdmessagefld->messagedatabuffer, hello_string
> - , (int16_t)strlen(hello_string));
> - }
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> + memcpy(pcmdmessagefld->messagedatabuffer,
> + hello_string, (int16_t)strlen(hello_string));
> break;
> -
> - case ARCMSR_MESSAGE_SAY_GOODBYE:
> - if(acb->fw_flag == FW_DEADLOCK) {
> + }
> + case ARCMSR_MESSAGE_SAY_GOODBYE: {
> + if (acb->fw_flag == FW_DEADLOCK)
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> arcmsr_iop_parking(acb);
> break;
> -
> - case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
> - if(acb->fw_flag == FW_DEADLOCK) {
> + }
> + case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: {
> + if (acb->fw_flag == FW_DEADLOCK)
> pcmdmessagefld->cmdmessage.ReturnCode =
> - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> - }
> + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
> + else
> + pcmdmessagefld->cmdmessage.ReturnCode =
> + ARCMSR_MESSAGE_RETURNCODE_OK;
> arcmsr_flush_adapter_cache(acb);
> break;
> -
> + }
> default:
> retvalue = ARCMSR_MESSAGE_FAIL;
> + pr_info("%s: unknown controlcode!\n", __func__);
> + }
> +message_out:
> + if (use_sg) {
> + struct scatterlist *sg;
> + sg = scsi_sglist(cmd);
> + kunmap_atomic(buffer - sg->offset);
> }
> - message_out:
> - sg = scsi_sglist(cmd);
> - kunmap_atomic(buffer - sg->offset);
> return retvalue;
> }
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2014-08-22 16:00 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-19 7:17 [PATCH v3 13/17] arcmsr: fix ioctl data read/write error for adapter type C Ching Huang
2014-08-22 16:00 ` Tomas Henzl [this message]
2014-08-25 17:59 ` Ching Huang
2014-08-25 10:29 ` Tomas Henzl
2014-08-25 12:52 ` Tomas Henzl
2014-08-26 20:27 ` Ching Huang
2014-08-26 13:20 ` Tomas Henzl
2014-08-27 20:19 ` Ching Huang
2014-08-27 12:29 ` Tomas Henzl
2014-08-28 11:40 ` Ching Huang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53F7690D.5070007@redhat.com \
--to=thenzl@redhat.com \
--cc=agordeev@redhat.com \
--cc=ching2048@areca.com.tw \
--cc=dan.carpenter@oracle.com \
--cc=hch@infradead.org \
--cc=jbottomley@parallels.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.