From: "NickCheng" <nick.cheng@areca.com.tw>
To: <linux-scsi@vger.kernel.org>
Cc: <linux-kernel@vger.kernel.org>, <jejb@kernel.org>
Subject: [PATCH 5/5] arcmsr: Modify ARC-1214 IO Behavior
Date: Thu, 15 Nov 2012 15:33:00 +0800 [thread overview]
Message-ID: <FD8DEE8B2A7541878C07E36B950DB79D@arecaaebe11fae> (raw)
[-- Attachment #1: Type: text/plain, Size: 166 bytes --]
From: Nick Cheng <nick.cheng@areca.com.tw>
Modify ARC-1214 IO behavior to make up for HW seldom malfunction.
Signed-off-by: Nick Cheng <nick.cheng@areca.com.tw>
---
[-- Attachment #2: patch5 --]
[-- Type: application/octet-stream, Size: 16628 bytes --]
diff -uprN a//drivers/scsi/arcmsr/arcmsr.h b//drivers/scsi/arcmsr/arcmsr.h
--- a//drivers/scsi/arcmsr/arcmsr.h 2012-11-15 12:12:19.035557259 +0800
+++ b//drivers/scsi/arcmsr/arcmsr.h 2012-11-15 15:04:34.291456858 +0800
@@ -63,6 +63,7 @@ struct device_attribute;
#define ARCMSR_DEFAULT_SG_ENTRIES 38
#define ARCMSR_MAX_HBB_POSTQUEUE 264
#define ARCMSR_MAX_ARC1214_POSTQUEUE 256
+#define ARCMSR_MAX_ARC1214_DONEQUEUE 257
#define ARCMSR_MAX_XFER_LEN 0x26000
#define ARCMSR_CDB_SG_PAGE_LENGTH 256
#define ARCMST_NUM_MSIX_VECTORS 4
@@ -175,8 +176,8 @@ struct SG64ENTRY
*/
struct QBUFFER
{
- uint32_t data_len;
- uint8_t data[124];
+ uint32_t __iomem data_len;
+ uint8_t __iomem data[124];
};
/*
*******************************************************************************
@@ -565,7 +566,7 @@ struct OutBound_SRB {
struct MessageUnit_D {
struct InBound_SRB post_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
- struct OutBound_SRB done_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
+ struct OutBound_SRB done_qbuffer[ARCMSR_MAX_ARC1214_DONEQUEUE];
u16 postq_index;
u16 doneq_index;
u32 __iomem *chip_id; //0x00004
@@ -618,6 +619,7 @@ struct AdapterControlBlock
spinlock_t eh_lock;
spinlock_t ccblist_lock;
spinlock_t postq_lock;
+ spinlock_t doneq_lock;
spinlock_t rqbuffer_lock;
spinlock_t wqbuffer_lock;
union {
@@ -671,15 +673,15 @@ struct AdapterControlBlock
unsigned int uncache_size;
uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
/* data collection buffer for read from 80331 */
- int32_t rqbuf_firstindex;
+ uint32_t rqbuf_firstindex;
/* first of read buffer */
- int32_t rqbuf_lastindex;
+ uint32_t rqbuf_lastindex;
/* last of read buffer */
uint8_t wqbuffer[ARCMSR_MAX_QBUFFER];
/* data collection buffer for write to 80331 */
- int32_t wqbuf_firstindex;
+ uint32_t wqbuf_firstindex;
/* first of write buffer */
- int32_t wqbuf_lastindex;
+ uint32_t wqbuf_lastindex;
/* last of write buffer */
uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
/* id0 ..... id15, lun0...lun7 */
diff -uprN a//drivers/scsi/arcmsr/arcmsr_hba.c b//drivers/scsi/arcmsr/arcmsr_hba.c
--- a//drivers/scsi/arcmsr/arcmsr_hba.c 2012-11-15 12:12:40.851557048 +0800
+++ b//drivers/scsi/arcmsr/arcmsr_hba.c 2012-11-15 15:04:34.319456858 +0800
@@ -1106,6 +1106,7 @@ static int arcmsr_probe(struct pci_dev *
spin_lock_init(&acb->eh_lock);
spin_lock_init(&acb->ccblist_lock);
spin_lock_init(&acb->postq_lock);
+ spin_lock_init(&acb->doneq_lock);
spin_lock_init(&acb->rqbuffer_lock);
spin_lock_init(&acb->wqbuffer_lock);
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
@@ -1247,6 +1248,7 @@ arcmsr_hbaB_abort_allcmd(struct AdapterC
}
return true;
}
+
static uint8_t
arcmsr_hbaC_abort_allcmd(struct AdapterControlBlock *pACB)
{
@@ -1261,6 +1263,7 @@ arcmsr_hbaC_abort_allcmd(struct AdapterC
}
return true;
}
+
static uint8_t
arcmsr_hbaD_abort_allcmd(struct AdapterControlBlock *pACB)
{
@@ -1274,6 +1277,7 @@ arcmsr_hbaD_abort_allcmd(struct AdapterC
}
return true;
}
+
static uint8_t
arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
{
@@ -1554,29 +1558,29 @@ arcmsr_done4abort_postqueue(struct Adapt
uint32_t doneq_index, index_stripped, addressLow, residual;
bool error;
struct CommandControlBlock *pCCB;
- outbound_write_pointer = ioread32(pmu->outboundlist_copy_pointer);
+ outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
residual = atomic_read(&acb->ccboutstandingcount);
for (i = 0; i < residual; i++) {
- while ((doneq_index & 0xFF) != (outbound_write_pointer & 0xFF)) {
+ while ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
if (doneq_index & 0x4000) {
- index_stripped = doneq_index & 0xFF;
+ index_stripped = doneq_index & 0xFFF;
index_stripped += 1;
index_stripped %=
- ARCMSR_MAX_ARC1214_POSTQUEUE;
+ ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped ?
- (index_stripped | 0x4000) : index_stripped;
+ (index_stripped | 0x4000) : (index_stripped + 1);
} else {
index_stripped = doneq_index;
index_stripped += 1;
index_stripped %=
- ARCMSR_MAX_ARC1214_POSTQUEUE;
+ ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index =
- index_stripped ? index_stripped : (index_stripped | 0x4000);
+ index_stripped ? index_stripped : ((index_stripped | 0x4000) + 1);
}
doneq_index = pmu->doneq_index;
addressLow =
- pmu->done_qbuffer[doneq_index & 0xFF].addressLow;
+ pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
pARCMSR_CDB = (struct ARCMSR_CDB *)
(acb->vir2phy_offset + ccb_cdb_phy);
@@ -1591,7 +1595,7 @@ arcmsr_done4abort_postqueue(struct Adapt
}
mdelay(10);
outbound_write_pointer =
- ioread32(pmu->outboundlist_copy_pointer);
+ pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
}
pmu->postq_index = 0;
@@ -2148,10 +2152,9 @@ struct QBUFFER __iomem
void
arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
{
- uint8_t __iomem *iop_data;
+ uint8_t __iomem *iop_data, *pQbuffer, *vaddr, *temp;
struct QBUFFER __iomem *prbuffer;
- struct QBUFFER *pQbuffer;
- int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+ int32_t my_empty_len, data_len, rqbuf_firstindex, rqbuf_lastindex;
unsigned long flags;
spin_lock_irqsave(&acb->rqbuffer_lock, flags);
@@ -2159,22 +2162,33 @@ arcmsr_iop2drv_data_wrote_handle(struct
rqbuf_firstindex = acb->rqbuf_firstindex;
prbuffer = arcmsr_get_iop_rqbuffer(acb);
iop_data = (uint8_t __iomem *)prbuffer->data;
- iop_len = prbuffer->data_len;
+ data_len = prbuffer->data_len;
my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) &
(ARCMSR_MAX_QBUFFER - 1);
- 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;
- iop_data++;
- iop_len--;
+ if (my_empty_len >= data_len) {
+ if (data_len > 0) {
+ temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+ memcpy(vaddr, iop_data, data_len);
+ smp_mb();
+ pQbuffer = &acb->rqbuffer[rqbuf_lastindex];
+ if ((rqbuf_lastindex + data_len)
+ > ARCMSR_MAX_QBUFFER) {
+ memcpy(pQbuffer, temp, ARCMSR_MAX_QBUFFER
+ - rqbuf_lastindex);
+ temp += (ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+ rqbuf_lastindex = (rqbuf_lastindex + data_len)
+ % ARCMSR_MAX_QBUFFER;
+ memcpy(&acb->rqbuffer[0], temp, rqbuf_lastindex);
+ } else {
+ memcpy(pQbuffer, temp, data_len);
+ rqbuf_lastindex = (rqbuf_lastindex + data_len)
+ % ARCMSR_MAX_QBUFFER;
+ }
+ kfree(vaddr);
}
- acb->rqbuf_lastindex = rqbuf_lastindex;
- arcmsr_iop_message_read(acb);
+ acb->rqbuf_lastindex = rqbuf_lastindex;
+ arcmsr_iop_message_read(acb);/*notice IOP the message is read*/
} else {
acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
}
@@ -2238,6 +2252,7 @@ arcmsr_hbaA_doorbell_isr(struct AdapterC
(ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK
| ARCMSR_OUTBOUND_IOP331_DATA_READ_OK));
}
+
static void
arcmsr_hbaC_doorbell_isr(struct AdapterControlBlock *pACB)
{
@@ -2392,28 +2407,30 @@ arcmsr_hbaD_postqueue_isr(struct Adapter
struct MessageUnit_D __iomem *pmu;
struct ARCMSR_CDB *arcmsr_cdb;
struct CommandControlBlock *ccb;
+ unsigned long flags;
+ spin_lock_irqsave(&acb->doneq_lock, flags);
pmu = (struct MessageUnit_D *)acb->pmuD;
- outbound_write_pointer = ioread32(pmu->outboundlist_copy_pointer);
+ outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
- if ((doneq_index & 0xFF) != (outbound_write_pointer & 0xFF)) {
+ if ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
do {
if (doneq_index & 0x4000) {
- index_stripped = doneq_index & 0xFF;
+ index_stripped = doneq_index & 0xFFF;
index_stripped += 1;
- index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+ index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped
- ? (index_stripped | 0x4000) : index_stripped;
+ ? (index_stripped | 0x4000) : (index_stripped + 1);
} else {
index_stripped = doneq_index;
index_stripped += 1;
- index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+ index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped
- ? index_stripped : (index_stripped | 0x4000);
+ ? index_stripped : ((index_stripped | 0x4000) + 1);
}
doneq_index = pmu->doneq_index;
addressLow =
- pmu->done_qbuffer[doneq_index & 0xFF].addressLow;
+ pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
+ ccb_cdb_phy);
@@ -2424,12 +2441,13 @@ arcmsr_hbaD_postqueue_isr(struct Adapter
arcmsr_drain_donequeue(acb, ccb, error);
iowrite32(doneq_index,
pmu->outboundlist_read_pointer);
- } while ((doneq_index & 0xFF) !=
- (outbound_write_pointer & 0xFF));
+ } while ((doneq_index & 0xFFF) !=
+ (outbound_write_pointer & 0xFFF));
}
iowrite32(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR,
pmu->outboundlist_interrupt_cause);
ioread32(pmu->outboundlist_interrupt_cause);
+ spin_unlock_irqrestore(&acb->doneq_lock, flags);
}
static void
@@ -2440,6 +2458,7 @@ arcmsr_hbaA_message_isr(struct AdapterCo
iowrite32(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
+
static void
arcmsr_hbaB_message_isr(struct AdapterControlBlock *acb)
{
@@ -2694,33 +2713,96 @@ arcmsr_iop_message_xfer(struct AdapterCo
}
ptmpQbuffer = ver_addr;
spin_lock_irqsave(&acb->rqbuffer_lock, flags);
- while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
- && (allxfer_len < 1031)) {
+ 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;
+ 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;
+ }
+ }
}
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;
+ uint8_t __iomem *iop_data, *vaddr, *temp;
+ uint32_t data_len, rqbuf_lastindex;
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ rqbuf_lastindex = acb->rqbuf_lastindex;
prbuffer = arcmsr_get_iop_rqbuffer(acb);
- iop_data = prbuffer->data;
- iop_len = ioread32(&prbuffer->data_len);
- while (iop_len > 0) {
- acb->rqbuffer[acb->rqbuf_lastindex] =
- ioread8(iop_data);
- acb->rqbuf_lastindex++;
- acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- iop_len--;
+ iop_data = (uint8_t __iomem *)prbuffer->data;
+ data_len = ioread32(&prbuffer->data_len);
+ if (data_len > 0) {
+ temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+ memcpy(vaddr, iop_data, data_len);
+ smp_mb();
+ pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
+ if ((rqbuf_lastindex + data_len) >
+ ARCMSR_MAX_QBUFFER) {
+ memcpy(pQbuffer, temp,
+ ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+ temp += (ARCMSR_MAX_QBUFFER
+ - rqbuf_lastindex);
+ rqbuf_lastindex = (rqbuf_lastindex
+ + data_len) % ARCMSR_MAX_QBUFFER;
+ memcpy(&acb->rqbuffer[0],
+ temp, rqbuf_lastindex);
+ } else {
+ memcpy(pQbuffer, temp, data_len);
+ rqbuf_lastindex = (rqbuf_lastindex +
+ data_len) % ARCMSR_MAX_QBUFFER;
+ }
+ kfree(vaddr);
}
+ acb->rqbuf_lastindex = rqbuf_lastindex;
arcmsr_iop_message_read(acb);
}
spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
@@ -3641,19 +3723,21 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
{
bool error;
uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb, ccb_cdb_phy;
- int rtn, index, outbound_write_pointer;
+ int rtn, doneq_index, index_stripped, outbound_write_pointer;
+ unsigned long flags;
struct ARCMSR_CDB *arcmsr_cdb;
struct CommandControlBlock *pCCB;
- struct MessageUnit_D __iomem *reg =
+ struct MessageUnit_D __iomem *pmu =
(struct MessageUnit_D *)acb->pmuD;
+ spin_lock_irqsave(&acb->doneq_lock, flags);
polling_hbaD_ccb_retry:
poll_count++;
while (1) {
outbound_write_pointer =
- ioread32(reg->outboundlist_copy_pointer);
- index = reg->doneq_index;
- if ((outbound_write_pointer & 0xFF) == index) {
+ pmu->done_qbuffer[0].addressLow + 1;
+ doneq_index = pmu->doneq_index;
+ if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
if (poll_ccb_done) {
rtn = SUCCESS;
break;
@@ -3666,17 +3750,27 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
goto polling_hbaD_ccb_retry;
}
}
- flag_ccb = reg->done_qbuffer[index].addressLow;
+ if (doneq_index & 0x4000) {
+ index_stripped = doneq_index & 0xFFF;
+ index_stripped += 1;
+ index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+ pmu->doneq_index = index_stripped ? (index_stripped | 0x4000)
+ : (index_stripped + 1);
+ } else {
+ index_stripped = doneq_index;
+ index_stripped += 1;
+ index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+ pmu->doneq_index = index_stripped ? index_stripped :
+ ((index_stripped | 0x4000) + 1);
+ }
+ doneq_index = pmu->doneq_index;
+ flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset +
ccb_cdb_phy);
pCCB = container_of(arcmsr_cdb,
struct CommandControlBlock, arcmsr_cdb);
poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
- index++;
- index %= ARCMSR_MAX_ARC1214_POSTQUEUE;
- reg->doneq_index = index;
- /* check if command done with no error*/
if ((pCCB->acb != acb) ||
(pCCB->startdone != ARCMSR_CCB_START)) {
if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
@@ -3703,6 +3797,7 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
? true : false;
arcmsr_report_ccb_state(acb, pCCB, error);
}
+ spin_unlock_irqrestore(&acb->doneq_lock, flags);
return rtn;
}
@@ -3838,7 +3933,7 @@ arcmsr_iop_confirm(struct AdapterControl
struct MessageUnit_D *reg =
(struct MessageUnit_D *)acb->pmuD;
reg->postq_index = 0;
- reg->doneq_index = 0x40FF;
+ reg->doneq_index = 0;
rwbuffer = reg->msgcode_rwbuffer;
iowrite32(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
iowrite32(cdb_phyaddr_hi32, rwbuffer++);
next reply other threads:[~2012-11-15 7:33 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-15 7:33 NickCheng [this message]
2012-11-16 11:56 NickCheng
2012-11-30 9:18 ` James Bottomley
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=FD8DEE8B2A7541878C07E36B950DB79D@arecaaebe11fae \
--to=nick.cheng@areca.com.tw \
--cc=jejb@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®