Hi Don/Kevin,

some comments inline (mostly stulistic nothing architectural)

On Thu, Jun 16, 2016 at 05:48:16PM -0500, Don Brace wrote:
> From: Kevin Barnett <kevin.barn...@microsemi.com>
> 
> This initial commit contains WIP of Microsemi's smartpqi module.
> 
> Reviewed-by: Scott Benesh <scott.ben...@microsemi.com>
> Reviewed-by: Kevin Barnett <kevin.barn...@microsemi.com>

if this is From: Kevin it should have his S-o-b as well.

> Signed-off-by: Don Brace <don.br...@microsemi.com>
> ---

[...]

> + */
> +
> +#if !defined(_SMARTPQI_H)
> +#define _SMARTPQI_H
> +
> +#pragma pack(1)

I know GCC does understand #pragma pack() to be compatible with MSVC but please
use the kernel's __packed convention on structs you want to have packed.

> +
> +#define PQI_DEVICE_SIGNATURE "PQI DREG"

[...]

> +     pqi_index_t     oq_ci_copy;
> +     struct task_struct *task;
> +     u16             int_msg_num;
> +};
> +

Just for clarification (sorry haven't looked up the sepecs yet) is this a
queue pair or more than two queues (looks like 3 to me)? 

> +struct pqi_queue_group {
> +     struct pqi_ctrl_info *ctrl_info;        /* backpointer */
> +     u16             iq_id[2];
> +     u16             oq_id;

[...]

> +#define RAID_CTLR_LUNID              "\0\0\0\0\0\0\0\0"
> +
> +struct pqi_scsi_dev_t {

For sake of consistency with the other structs "struct pqi_scsi_dev"? 

> +     int     devtype;                /* as reported by INQUIRY commmand */
> +     u8      device_type;            /* as reported by */

[...]

> +
> +/* Define the PCI IDs for the controllers that we support. */
> +static const struct pci_device_id pqi_pci_id_table[] = {
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0110,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0600,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0601,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0602,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0603,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0650,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0651,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0652,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0653,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0654,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0655,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0700,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x0701,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0800,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0801,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0802,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0803,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0804,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0805,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0900,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0901,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0902,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0903,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0904,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0905,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .subdevice = 0x0906,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x1001,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x1100,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x1101,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x1102,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_VENDOR_ID_HP,
> +             .subdevice = 0x1150,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     {
> +             .vendor = PCI_VENDOR_ID_ADAPTEC2,
> +             .device = 0x028f,
> +             .subvendor = PCI_ANY_ID,
> +             .subdevice = PCI_ANY_ID,
> +             .class = 0,
> +             .class_mask = 0,
> +             .driver_data = 0
> +     },
> +     { 0 }
> +};


The above table can be drastically reduced by using the PCI_DEVICE_SUB() macro:
static const struct pci_device_id pqi_pci_id_table[] = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x28f, PCI_VENDOR_ID_ADAPTEC2, 
0x0110) },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x28f, PCI_VENDOR_ID_HP, 
0x0600) },
        ...

Also I think it makes more sense near the struct pci_driver way down, as
that's the place it's actuall used.

> +MODULE_DEVICE_TABLE(pci, pqi_pci_id_table);
> +
> +static struct {
> +     atomic_t        num_requests[2];
> +     atomic_t        num_raid_bypasses;
> +     atomic_t        num_outstanding_requests[2];
> +     atomic_t        num_passthru_ioctls;
> +     atomic_t        num_heartbeat_events;
> +     atomic_t        num_all_other_events;
> +     atomic_t        num_scans;
> +     atomic_t        num_interrupts;
> +     atomic_t        num_spurious_interrupts;
> +     atomic_t        num_alloc_io_request_collisions;
> +     atomic_t        num_spans[2];
> +     atomic_t        num_interrupts_wrong_cpu;
> +} pqi_statistics = {
> +     .num_requests[0] = ATOMIC_INIT(0),
> +     .num_requests[1] = ATOMIC_INIT(0),
> +     .num_raid_bypasses = ATOMIC_INIT(0),
> +     .num_outstanding_requests[0] = ATOMIC_INIT(0),
> +     .num_outstanding_requests[1] = ATOMIC_INIT(0),
> +     .num_passthru_ioctls = ATOMIC_INIT(0),
> +     .num_heartbeat_events = ATOMIC_INIT(0),
> +     .num_all_other_events = ATOMIC_INIT(0),
> +     .num_scans = ATOMIC_INIT(0),
> +     .num_interrupts = ATOMIC_INIT(0),
> +     .num_spurious_interrupts = ATOMIC_INIT(0),
> +     .num_alloc_io_request_collisions = ATOMIC_INIT(0),
> +     .num_spans[0] = ATOMIC_INIT(0),
> +     .num_spans[1] = ATOMIC_INIT(0),
> +     .num_interrupts_wrong_cpu = ATOMIC_INIT(0),
> +};

Appart from Hannes' comments, I wonder if it really makes sense to have these
statistics on a driver global basis, not per adapter?

> +
> +static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info);

[...]

> +static ssize_t pqi_statistics_show(struct device *dev,
> +     struct device_attribute *attr, char *buffer)
> +{
> +     ssize_t count = 0;
> +     unsigned int num_raid_requests;
> +     unsigned int num_aio_requests;
> +     unsigned int num_outstanding_raid_requests = 0;
> +     unsigned int num_outstanding_aio_requests = 0;
> +     struct pqi_ctrl_info *ctrl_info;
> +     struct Scsi_Host *shost;
> +
> +     shost = class_to_shost(dev);
> +     ctrl_info = shost_to_hba(shost);
> +
> +     num_raid_requests =
> +             atomic_read(&pqi_statistics.num_requests[RAID_PATH]);
> +     num_aio_requests = atomic_read(&pqi_statistics.num_requests[AIO_PATH]);
> +
> +     num_outstanding_raid_requests =
> +     atomic_read(&pqi_statistics.num_outstanding_requests[RAID_PATH]);
> +     num_outstanding_aio_requests =
> +     atomic_read(&pqi_statistics.num_outstanding_requests[AIO_PATH]);
> +
> +     if (pqi_ctrl_offline(ctrl_info))
> +             count += snprintf(buffer + count, PAGE_SIZE - count,
> +                     "*** CONTROLLER OFFLINE ***\n");
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "            total requests: %u\n",
> +             num_raid_requests + num_aio_requests);
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "       total RAID requests: %u\n",
> +             num_raid_requests);
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "        total AIO requests: %u\n",
> +             num_aio_requests);
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "             RAID bypasses: %u\n",
> +             atomic_read(&pqi_statistics.num_raid_bypasses));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "total outstanding requests: %u\n",
> +             num_outstanding_raid_requests + num_outstanding_aio_requests);
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             " outstanding RAID requests: %u / %u\n",
> +             num_outstanding_raid_requests,
> +             ctrl_info->num_queue_groups *
> +             (ctrl_info->num_elements_per_iq - 1));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "  outstanding AIO requests: %u / %u\n",
> +             num_outstanding_aio_requests,
> +             ctrl_info->num_queue_groups *
> +             (ctrl_info->num_elements_per_iq - 1));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "        passthrough IOCTLs: %u\n",
> +             atomic_read(&pqi_statistics.num_passthru_ioctls));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "          heartbeat events: %u\n",
> +             atomic_read(&pqi_statistics.num_heartbeat_events));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "          all other events: %u\n",
> +             atomic_read(&pqi_statistics.num_all_other_events));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "                scan count: %u\n",
> +             atomic_read(&pqi_statistics.num_scans));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "                interrupts: %u\n",
> +             atomic_read(&pqi_statistics.num_interrupts));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "       spurious interrupts: %u\n",
> +             atomic_read(&pqi_statistics.num_spurious_interrupts));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "  alloc request collisions: %u\n",
> +             atomic_read(&pqi_statistics.num_alloc_io_request_collisions));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "                RAID spans: %u\n",
> +             atomic_read(&pqi_statistics.num_spans[RAID_PATH]));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "                 AIO spans: %u\n",
> +             atomic_read(&pqi_statistics.num_spans[AIO_PATH]));
> +
> +     count += snprintf(buffer + count, PAGE_SIZE - count,
> +             "   interrupts on wrong CPU: %u\n",
> +             atomic_read(&pqi_statistics.num_interrupts_wrong_cpu));
> +
> +     return count;
> +}

Wasn't the sysfs rule one entry per file?

> +
> +static ssize_t pqi_devices_show(struct device *dev,
> +     struct device_attribute *attr, char *buffer)
> +{

[...]

> +     rc = pqi_build_raid_path_request(ctrl_info, &request,
> +             SA_CACHE_FLUSH, RAID_CTLR_LUNID, buffer,
> +             SA_CACHE_FLUSH_BUFFER_LENGTH, 0, &pci_direction);
> +     if (rc)
> +             goto out;
> +
> +     rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
> +             0, NULL, NO_TIMEOUT);

So if this is called via the shutdown() -> pqi_shutdown() path it /may/ block
shutdown infinitely? I'm not shure this is what people want.

> +
> +     pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
> +             pci_direction);
> +
> +out:
> +     kfree(buffer);
> +

[...]

> +static void pqi_complete_queued_requests(struct pqi_ctrl_info *ctrl_info,
> +     struct pqi_scsi_dev_t *device_in_reset)
> +{
> +     unsigned int i;
> +     unsigned int path;
> +     struct pqi_queue_group *queue_group;
> +     unsigned long flags;
> +     struct pqi_io_request *io_request;
> +     struct pqi_io_request *next;
> +     struct scsi_cmnd *scmd;
> +     struct pqi_scsi_dev_t *device;
> +
> +     for (i = 0; i < ctrl_info->num_queue_groups; i++) {
> +             queue_group = &ctrl_info->queue_groups[i];
> +
> +             for (path = 0; path < 2; path++) {
> +                     spin_lock_irqsave(&queue_group->submit_lock[path],
> +                             flags);
> +
> +                     list_for_each_entry_safe(io_request, next,
> +                             &queue_group->request_list[path],
> +                             request_list_entry) {
> +                             scmd = io_request->scmd;
> +                             if (scmd) {
> +                                     device = scmd->device->hostdata;
> +                                     if (device == device_in_reset) {
> +                                             set_host_byte(scmd, DID_RESET);
> +                                             pqi_scsi_done(scmd);
> +                                             list_del(&io_request->
> +                                                     request_list_entry);
> +                                     }
> +                             }
> +                     }
> +
> +                     spin_unlock_irqrestore(&queue_group->submit_lock[path],
> +                             flags);
> +             }

If you'd factor the inner for loop into an own small (inline) function, it
could drastically improve readability here.

something like 

static void pqi_complete_queue_group(struct pqi_queue_group *qg, struct
                                     pqi_device_t *device_in_reset)
{
        unsigned int path;
        unsigned long flags;
        struct qpi_scsi_dev_t *dev;
        struct pqi_io_request *ior, *next;

        for (path = 0; path < 2; path++) {
                spin_lock_irqsave(&qg->submit_lock[path], flags);

                list_for_each_entry_save(ior, next, &qg->request_list[path],
                                         request_list_entry) {
                        scmd = ior->scmnd;
                        if (!scmd) 
                                continue;

                        device = scmnd->device->hostdata;
                        if (dev == device_in_reset) {
                                set_host_byte(scmnd, DID_RESET);
                                pqi_scsi_done(scmnd);
                                list_del(&ior->request_list_entry);
                        }
                }
                spin_unlock_irqresetore(&qg->submit_lock[path], flags);
        }
}

> +     }
> +}
> +

[..]

> +
> +static DEVICE_ATTR(sas_address, S_IRUGO, pqi_sas_address_show, NULL);
> +static DEVICE_ATTR(ssd_smart_path_enabled, S_IRUGO,
> +     pqi_ssd_smart_path_enabled_show, NULL);
> +
> +static struct device_attribute *pqi_sdev_attrs[] = {
> +     &dev_attr_sas_address,
> +     &dev_attr_ssd_smart_path_enabled,
> +     NULL
> +};
> +
> +static DEVICE_ATTR(rescan, S_IWUSR, NULL, pqi_host_store_rescan);
> +static DEVICE_ATTR(stats, S_IRUGO, pqi_statistics_show, NULL);
> +static DEVICE_ATTR(devices, S_IRUGO, pqi_devices_show, NULL);
> +static DEVICE_ATTR(version, S_IRUGO, pqi_version_show, NULL);
> +static DEVICE_ATTR(pqi, S_IRUGO, pqi_info_show, NULL);
> +
> +static struct device_attribute *pqi_shost_attrs[] = {
> +     &dev_attr_rescan,
> +     &dev_attr_stats,
> +     &dev_attr_devices,
> +     &dev_attr_version,
> +     &dev_attr_pqi,
> +     NULL
> +};

This should be somewhere near the functions implementing the sysfs show
callbacks.

> +
> +static int pqi_change_queue_depth(struct scsi_device *sdev, int qdepth)
> +{
> +     struct pqi_scsi_dev_t *device = sdev->hostdata;

[...]

-- 
Johannes Thumshirn                                          Storage
jthumsh...@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to