From: Andi Kleen <andi@firstfloor.org>
To: linux-scsi@vger.kernel.org, James.Bottomley@HansenPartnership.com
Subject: [PATCH] [7/22] Remove unchecked_isa_dma in aha152x/wd7000/sym53c416/u14-34f/NCR53c406a
Date: Mon, 25 Feb 2008 00:35:20 +0100 (CET) [thread overview]
Message-ID: <20080224233520.198171B4183@basil.firstfloor.org> (raw)
In-Reply-To: <200802251235.889863872@firstfloor.org>
I lumped these all together because these old ISA only drivers all look
very unmaintained and the changes were relatively simple.
I audited them for possible use of unchecked_isa_dma and fixed the cases
who needed them:
- Allocate separate dma'able hostdata when needed
- Checked that they all always copy ->cmnd
- Checked if they need sense_buffer bouncing and enable when needed
(i'm not 100% sure what it means if a driver does not reference
sense_buffer, but all except ultrastor and u14-34f do not)
- Add a explicit slave_alloc callback to enable block layer bouncing
Untested due to lack of hardware.
Signed-off-by: Andi Kleen <ak@suse.de>
---
drivers/scsi/NCR53c406a.c | 8 ++++++-
drivers/scsi/aha152x.c | 22 ++++++++++++++++---
drivers/scsi/sym53c416.c | 9 +++++++
drivers/scsi/u14-34f.c | 52 +++++++++++++++++++++++++++++++++++-----------
drivers/scsi/ultrastor.c | 13 ++++++++---
drivers/scsi/wd7000.c | 45 +++++++++++++++++++++++++--------------
6 files changed, 113 insertions(+), 36 deletions(-)
Index: linux/drivers/scsi/aha152x.c
===================================================================
--- linux.orig/drivers/scsi/aha152x.c
+++ linux/drivers/scsi/aha152x.c
@@ -551,6 +551,9 @@ struct aha152x_hostdata {
struct list_head host_list;
};
+struct aha152x_hostdata_ptr {
+ struct aha152x_hostdata *host;
+};
/*
* host specific command extension
@@ -564,7 +567,7 @@ struct aha152x_scdata {
/* access macros for hostdata */
-#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)
+#define HOSTDATA(shpnt) (((struct aha152x_hostdata_ptr *) shost_priv(shpnt))->host)
#define HOSTNO ((shpnt)->host_no)
@@ -771,13 +774,22 @@ static irqreturn_t swintr(int irqno, voi
struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
{
struct Scsi_Host *shpnt;
+ struct aha152x_hostdata *host;
- shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
+ shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata_ptr));
if (!shpnt) {
printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
return NULL;
}
+ host = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA,
+ get_order(sizeof(struct aha152x_hostdata)));
+ if (!host) {
+ scsi_host_put(shpnt);
+ printk(KERN_ERR "aha152x: dma alloc of hostdata failed\n");
+ return NULL;
+ }
+
memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
@@ -899,6 +911,8 @@ struct Scsi_Host *aha152x_probe_one(stru
out_host_put:
list_del(&HOSTDATA(shpnt)->host_list);
+ free_pages((unsigned long)HOSTDATA(shpnt),
+ get_order(sizeof(struct aha152x_hostdata)));
scsi_host_put(shpnt);
return NULL;
@@ -924,6 +938,8 @@ void aha152x_release(struct Scsi_Host *s
#endif
list_del(&HOSTDATA(shpnt)->host_list);
+ free_pages((unsigned long)HOSTDATA(shpnt),
+ get_order(sizeof(struct aha152x_hostdata)));
scsi_host_put(shpnt);
}
@@ -3456,7 +3472,7 @@ static int aha152x_proc_info(struct Scsi
static int aha152x_adjust_queue(struct scsi_device *device)
{
- blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_ISA);
return 0;
}
Index: linux/drivers/scsi/wd7000.c
===================================================================
--- linux.orig/drivers/scsi/wd7000.c
+++ linux/drivers/scsi/wd7000.c
@@ -189,7 +189,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsicam.h>
-
#undef WD7000_DEBUG /* general debug */
#ifdef WD7000_DEBUG
#define dprintk printk
@@ -260,6 +259,12 @@ typedef struct adapter {
unchar rev1, rev2; /* filled in by wd7000_revision */
} Adapter;
+struct adapter_ptr {
+ Adapter *host;
+};
+
+#define wd_host(shost) (((struct adapter_ptr *)shost_priv(shost))->host)
+
/*
* (linear) base address for ROM BIOS
*/
@@ -1092,7 +1097,7 @@ static int wd7000_queuecommand(struct sc
unchar idlun;
short cdblen;
int nseg;
- Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
+ Adapter *host = wd_host(SCpnt->device->host);
cdblen = SCpnt->cmd_len;
idlun = ((SCpnt->device->id << 5) & 0xe0) | (SCpnt->device->lun & 7);
@@ -1312,7 +1317,7 @@ static int wd7000_set_info(char *buffer,
static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
{
- Adapter *adapter = (Adapter *)host->hostdata;
+ Adapter *adapter = wd_host(host);
unsigned long flags;
char *pos = buffer;
#ifdef WD7000_DEBUG
@@ -1485,18 +1490,16 @@ static __init int wd7000_detect(struct s
dprintk("ok!\n");
if (inb(iobase + ASC_INTR_STAT) == 1) {
- /*
- * We register here, to get a pointer to the extra space,
- * which we'll use as the Adapter structure (host) for
- * this adapter. It is located just after the registered
- * Scsi_Host structure (sh), and is located by the empty
- * array hostdata.
- */
- sh = scsi_register(tpnt, sizeof(Adapter));
+ sh = scsi_register(tpnt, sizeof(struct adapter_ptr));
if (sh == NULL)
goto err_release;
- host = (Adapter *) sh->hostdata;
+ host = (Adapter *)__get_free_pages(GFP_DMA|GFP_KERNEL,
+ get_order(sizeof(Adapter)));
+ if (!host)
+ goto err_unregister;
+
+ ((struct adapter_ptr *)shost_priv(sh))->host = host;
dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
memset(host, 0, sizeof(Adapter));
@@ -1513,7 +1516,7 @@ static __init int wd7000_detect(struct s
dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma);
if (!wd7000_init(host)) /* Initialization failed */
- goto err_unregister;
+ goto err_free_host;
/*
* OK from here - we'll use this adapter/configuration.
@@ -1540,6 +1543,8 @@ static __init int wd7000_detect(struct s
continue;
+ err_free_host:
+ free_pages((unsigned long)host, get_order(sizeof(Adapter)));
err_unregister:
scsi_unregister(sh);
err_release:
@@ -1559,6 +1564,8 @@ static int wd7000_release(struct Scsi_Ho
free_irq(shost->irq, NULL);
if (shost->io_port && shost->n_io_port)
release_region(shost->io_port, shost->n_io_port);
+ free_pages((unsigned long)wd_host(shost),
+ get_order(sizeof(Adapter)));
scsi_unregister(shost);
return 0;
}
@@ -1569,7 +1576,7 @@ static int wd7000_release(struct Scsi_Ho
*/
static int wd7000_abort(Scsi_Cmnd * SCpnt)
{
- Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
+ Adapter *host = wd_host(SCpnt->device->host);
if (inb(host->iobase + ASC_STAT) & INT_IM) {
printk("wd7000_abort: lost interrupt\n");
@@ -1586,7 +1593,7 @@ static int wd7000_abort(Scsi_Cmnd * SCpn
static int wd7000_host_reset(struct scsi_cmnd *SCpnt)
{
- Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
+ Adapter *host = wd_host(SCpnt->device->host);
spin_unlock_irq(SCpnt->device->host->host_lock);
@@ -1652,6 +1659,12 @@ static int wd7000_biosparam(struct scsi_
return (0);
}
+static int wd7000_adjust_queue(struct scsi_device *device)
+{
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_ISA);
+ return 0;
+}
+
MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
MODULE_LICENSE("GPL");
@@ -1669,7 +1682,7 @@ static struct scsi_host_template driver_
.this_id = 7,
.sg_tablesize = WD7000_SG,
.cmd_per_lun = 1,
- .unchecked_isa_dma = 1,
+ .slave_alloc = wd7000_adjust_queue,
.use_clustering = ENABLE_CLUSTERING,
};
Index: linux/drivers/scsi/NCR53c406a.c
===================================================================
--- linux.orig/drivers/scsi/NCR53c406a.c
+++ linux/drivers/scsi/NCR53c406a.c
@@ -1045,6 +1045,12 @@ static void __init calc_port_addr(void)
MODULE_LICENSE("GPL");
+static int NCR53c406a_adjust_queue(struct scsi_device *device)
+{
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_ISA);
+ return 0;
+}
+
/* NOTE: scatter-gather support only works in PIO mode.
* Use SG_NONE if DMA mode is enabled!
*/
@@ -1063,8 +1069,8 @@ static struct scsi_host_template driver_
.this_id = 7 /* SCSI ID of the chip */,
.sg_tablesize = 32 /*SG_ALL*/ /*SG_NONE*/,
.cmd_per_lun = 1 /* commands per lun */,
- .unchecked_isa_dma = 1 /* unchecked_isa_dma */,
.use_clustering = ENABLE_CLUSTERING,
+ .slave_alloc = NCR53c406a_adjust_queue,
};
#include "scsi_module.c"
Index: linux/drivers/scsi/u14-34f.c
===================================================================
--- linux.orig/drivers/scsi/u14-34f.c
+++ linux/drivers/scsi/u14-34f.c
@@ -439,6 +439,12 @@ static int u14_34f_bios_param(struct scs
sector_t, int *);
static int u14_34f_slave_configure(struct scsi_device *);
+static int u14_34f_adjust_queue(struct scsi_device *device)
+{
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_ISA);
+ return 0;
+}
+
static struct scsi_host_template driver_template = {
.name = "UltraStor 14F/34F rev. 8.10.00 ",
.detect = u14_34f_detect,
@@ -449,8 +455,9 @@ static struct scsi_host_template driver_
.bios_param = u14_34f_bios_param,
.slave_configure = u14_34f_slave_configure,
.this_id = 7,
- .unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .sense_buffer_mask = DMA_24BIT_MASK,
+ .slave_alloc = u14_34f_adjust_queue,
};
#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
@@ -606,6 +613,10 @@ struct hostdata {
char board_id[256]; /* data from INQUIRY on this board */
};
+struct hostdata_ptr {
+ struct hostdata *host;
+};
+
static struct Scsi_Host *sh[MAX_BOARDS + 1];
static const char *driver_name = "Ux4F";
static char sha[MAX_BOARDS];
@@ -627,7 +638,8 @@ static unsigned long io_port[] = {
0x0
};
-#define HD(board) ((struct hostdata *) &sh[board]->hostdata)
+#define HOSTDATA(shost) (((struct hostdata_ptr *)shost_priv(shost))->host)
+#define HD(board) HOSTDATA(sh[board])
#define BN(board) (HD(board)->board_name)
/* Device is Little Endian */
@@ -688,7 +700,7 @@ static int u14_34f_slave_configure(struc
char *tag_suffix, *link_suffix;
struct Scsi_Host *host = dev->host;
- j = ((struct hostdata *) host->hostdata)->board_number;
+ j = HOSTDATA(host)->board_number;
utqd = MAX_CMD_PER_LUN;
tqd = max_queue_depth;
@@ -798,6 +810,7 @@ static int port_detect \
unsigned char irq, dma_channel, subversion, i;
unsigned char in_byte;
char *bus_type, dma_name[16];
+ struct hostdata *host;
/* Allowed BIOS base addresses (NULL indicates reserved) */
unsigned long bios_segment_table[8] = {
@@ -887,13 +900,25 @@ static int port_detect \
if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;
spin_unlock_irq(&driver_lock);
- sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
+
+ host = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA,
+ get_order(sizeof(struct hostdata)));
+ if (!host) {
+ printk("%s: unable to allocate dma data\n", name);
+ spin_lock_irq(&driver_lock);
+ goto freedma;
+ }
+
+ sh[j] = scsi_register(tpnt, sizeof(struct hostdata_ptr));
+
spin_lock_irq(&driver_lock);
if (sh[j] == NULL) {
printk("%s: unable to register host, detaching.\n", name);
- goto freedma;
- }
+ goto freebounce;
+ }
+ HOSTDATA(sh[j]) = host;
+ memset(host, 0, sizeof(struct hostdata));
sh[j]->io_port = port_base;
sh[j]->unique_id = port_base;
@@ -931,14 +956,12 @@ static int port_detect \
if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
if (HD(j)->subversion == ESA) {
- sh[j]->unchecked_isa_dma = FALSE;
sh[j]->dma_channel = NO_DMA;
sprintf(BN(j), "U34F%d", j);
bus_type = "VESA";
}
else {
unsigned long flags;
- sh[j]->unchecked_isa_dma = TRUE;
flags=claim_dma_lock();
disable_dma(dma_channel);
@@ -980,7 +1003,7 @@ static int port_detect \
for (i = 0; i < sh[j]->can_queue; i++)
if (! ((&HD(j)->cp[i])->sglist = kmalloc(
sh[j]->sg_tablesize * sizeof(struct sg_list),
- (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
+ ((HD(j)->subversion != ESA) ? __GFP_DMA : 0) | GFP_ATOMIC))) {
printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
goto release;
}
@@ -1014,6 +1037,9 @@ static int port_detect \
return TRUE;
+freebounce:
+ free_pages((unsigned long)host,
+ get_order(sizeof(struct hostdata)));
freedma:
if (subversion == ISA) free_dma(dma_channel);
freeirq:
@@ -1250,7 +1276,7 @@ static int u14_34f_queuecommand(struct s
struct mscp *cpp;
/* j is the board number */
- j = ((struct hostdata *) SCpnt->device->host->hostdata)->board_number;
+ j = HOSTDATA(SCpnt->device->host)->board_number;
if (SCpnt->host_scribble)
panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
@@ -1329,7 +1355,7 @@ static int u14_34f_queuecommand(struct s
static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
unsigned int i, j;
- j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
+ j = HOSTDATA(SCarg->device->host)->board_number;
if (SCarg->host_scribble == NULL) {
scmd_printk(KERN_INFO, SCarg, "abort, pid %ld inactive.\n",
@@ -1396,7 +1422,7 @@ static int u14_34f_eh_host_reset(struct
int arg_done = FALSE;
struct scsi_cmnd *SCpnt;
- j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
+ j = HOSTDATA(SCarg->device->host)->board_number;
scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->serial_number);
spin_lock_irq(sh[j]->host_lock);
@@ -1961,6 +1987,8 @@ static int u14_34f_release(struct Scsi_H
free_dma(sh[j]->dma_channel);
release_region(sh[j]->io_port, sh[j]->n_io_port);
+ free_pages((unsigned long)HOSTDATA(sh[j]),
+ get_order(sizeof(struct hostdata)));
scsi_unregister(sh[j]);
return FALSE;
}
Index: linux/drivers/scsi/sym53c416.c
===================================================================
--- linux.orig/drivers/scsi/sym53c416.c
+++ linux/drivers/scsi/sym53c416.c
@@ -825,6 +825,12 @@ module_param_array(sym53c416_3, uint, NU
#endif
+static int sym53c416_adjust_queue(struct scsi_device *device)
+{
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_ISA);
+ return 0;
+}
+
static struct scsi_host_template driver_template = {
.proc_name = "sym53c416",
.name = "Symbios Logic 53c416",
@@ -838,7 +844,8 @@ static struct scsi_host_template driver_
.this_id = SYM53C416_SCSI_ID,
.sg_tablesize = 32,
.cmd_per_lun = 1,
- .unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .slave_alloc = sym53c416_adjust_queue,
+
};
#include "scsi_module.c"
Index: linux/drivers/scsi/ultrastor.c
===================================================================
--- linux.orig/drivers/scsi/ultrastor.c
+++ linux/drivers/scsi/ultrastor.c
@@ -350,6 +350,12 @@ static void log_ultrastor_abort(struct u
}
#endif
+static int ultrastor_adjust_queue(struct scsi_device *device)
+{
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_ISA);
+ return 0;
+}
+
static int ultrastor_14f_detect(struct scsi_host_template * tpnt)
{
size_t i;
@@ -501,7 +507,10 @@ static int ultrastor_14f_detect(struct s
config.dma_channel, config.ha_scsi_id, config.subversion);
#endif
tpnt->this_id = config.ha_scsi_id;
- tpnt->unchecked_isa_dma = (config.subversion != U34F);
+ if (config.subversion != U34F) {
+ tpnt->sense_buffer_mask = DMA_24BIT_MASK;
+ tpnt->slave_alloc = ultrastor_adjust_queue;
+ }
#if ULTRASTOR_MAX_CMDS > 1
config.mscp_free = ~0;
@@ -605,7 +614,6 @@ static int ultrastor_24f_detect(struct s
config.interrupt, config.ha_scsi_id);
#endif
tpnt->this_id = config.ha_scsi_id;
- tpnt->unchecked_isa_dma = 0;
tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG;
shpnt = scsi_register(tpnt, 0);
@@ -1202,7 +1210,6 @@ static struct scsi_host_template driver_
.can_queue = ULTRASTOR_MAX_CMDS,
.sg_tablesize = ULTRASTOR_14F_MAX_SG,
.cmd_per_lun = ULTRASTOR_MAX_CMDS_PER_LUN,
- .unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
};
#include "scsi_module.c"
next prev parent reply other threads:[~2008-02-24 23:51 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-24 23:35 [PATCH] [0/22] Remove isa_unchecked_dma and some more GFP_DMAs in the mid layer Andi Kleen
2008-02-24 23:35 ` [PATCH] [1/22] Add new sense_buffer_mask host template field Andi Kleen
2008-02-25 14:48 ` James Bottomley
2008-02-25 15:01 ` Andi Kleen
2008-02-24 23:35 ` [PATCH] [2/22] Remove unchecked_isa in BusLogic Andi Kleen
2008-02-24 23:35 ` [PATCH] [3/22] Remove unchecked_isa_dma in advansys.c Andi Kleen
2008-02-25 21:47 ` Matthew Wilcox
2008-02-25 22:40 ` Andi Kleen
2008-02-25 22:50 ` Matthew Wilcox
2008-02-25 22:54 ` Jeff Garzik
2008-02-25 22:58 ` James Bottomley
2008-02-26 3:44 ` Andi Kleen
2008-02-26 15:18 ` James Bottomley
2008-02-26 18:40 ` Matthew Wilcox
2008-02-26 13:56 ` Matthew Wilcox
2008-02-24 23:35 ` [PATCH] [4/22] Remove unchecked_isa_dma in gdth Andi Kleen
2008-02-24 23:35 ` [PATCH] [6/22] Remove unchecked_isa_dma in aha1542 Andi Kleen
2008-02-24 23:35 ` Andi Kleen [this message]
2008-02-24 23:35 ` [PATCH] [8/22] Remove random noop unchecked_isa_dma users Andi Kleen
2008-02-25 14:19 ` Salyzyn, Mark
2008-02-24 23:35 ` [PATCH] [10/22] Remove unchecked_isa_dma support for hostdata Andi Kleen
2008-02-24 23:35 ` [PATCH] [11/22] Remove unchecked_isa_dma checks in sg.c Andi Kleen
2008-02-24 23:35 ` [PATCH] [12/22] Remove GFP_DMAs/unchecked_isa_dma checks in scsi_scan.c Andi Kleen
2008-02-25 14:46 ` James Bottomley
2008-02-25 14:58 ` Andi Kleen
2008-02-25 15:04 ` James Bottomley
2008-02-25 15:11 ` Andi Kleen
2008-02-25 15:45 ` James Bottomley
2008-02-25 16:34 ` Andi Kleen
2008-02-24 23:35 ` [PATCH] [13/22] Don't disable direct_io for unchecked_isa_dma in st.c Andi Kleen
2008-02-24 23:35 ` [PATCH] [14/22] Remove automatic block layer bouncing for unchecked_isa_dma Andi Kleen
2008-02-24 23:35 ` [PATCH] [15/22] Remove GFP_DMA use in sr_ioctl Andi Kleen
2008-02-24 23:35 ` [PATCH] [16/22] Remove unchecked_isa_dma from sysfs Andi Kleen
2008-02-24 23:35 ` [PATCH] [17/22] Switch to a single SCSI command pool Andi Kleen
2008-02-24 23:35 ` [PATCH] [18/22] Finally remove unchecked_isa_dma support for Cmnds Andi Kleen
2008-02-24 23:35 ` [PATCH] [19/22] Finally kill unchecked_isa_dma Andi Kleen
2008-02-24 23:35 ` [PATCH] [20/22] Remove GFP_DMA in sr.c Andi Kleen
2008-02-24 23:35 ` [PATCH] [21/22] Remove GFP_DMA in ch.c Andi Kleen
2008-02-24 23:35 ` [PATCH] [22/22] Remove GFP_DMA in sr_vendor.c Andi Kleen
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=20080224233520.198171B4183@basil.firstfloor.org \
--to=andi@firstfloor.org \
--cc=James.Bottomley@HansenPartnership.com \
--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;
as well as URLs for NNTP newsgroup(s).