hptiop: Support HighPoint RR36xx HBAs and Support SAS tape and SAS media changer
Support HighPoint RR36xx HBAs which are based on Marvell Frey. Support SAS tape and SAS media changer. [jejb: remove now unused label] Signed-off-by: HighPoint Linux Team <linux@highpoint-tech.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <JBottomley@Odin.com>
This commit is contained in:
parent
442d75628a
commit
a93429c300
2 changed files with 67 additions and 40 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* HighPoint RR3xxx/4xxx controller driver for Linux
|
* HighPoint RR3xxx/4xxx controller driver for Linux
|
||||||
* Copyright (C) 2006-2012 HighPoint Technologies, Inc. All Rights Reserved.
|
* Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -42,7 +42,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
|
||||||
|
|
||||||
static char driver_name[] = "hptiop";
|
static char driver_name[] = "hptiop";
|
||||||
static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
|
static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
|
||||||
static const char driver_ver[] = "v1.8";
|
static const char driver_ver[] = "v1.10.0";
|
||||||
|
|
||||||
static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
|
static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
|
||||||
static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
|
static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
|
||||||
|
@ -764,9 +764,7 @@ static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
|
||||||
scsi_set_resid(scp,
|
scsi_set_resid(scp,
|
||||||
scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
|
scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
|
||||||
scp->result = SAM_STAT_CHECK_CONDITION;
|
scp->result = SAM_STAT_CHECK_CONDITION;
|
||||||
memcpy(scp->sense_buffer, &req->sg_list,
|
memcpy(scp->sense_buffer, &req->sg_list, SCSI_SENSE_BUFFERSIZE);
|
||||||
min_t(size_t, SCSI_SENSE_BUFFERSIZE,
|
|
||||||
le32_to_cpu(req->dataxfer_length)));
|
|
||||||
goto skip_resid;
|
goto skip_resid;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1037,8 +1035,9 @@ static int hptiop_queuecommand_lck(struct scsi_cmnd *scp,
|
||||||
|
|
||||||
scp->result = 0;
|
scp->result = 0;
|
||||||
|
|
||||||
if (scp->device->channel || scp->device->lun ||
|
if (scp->device->channel ||
|
||||||
scp->device->id > hba->max_devices) {
|
(scp->device->id > hba->max_devices) ||
|
||||||
|
((scp->device->id == (hba->max_devices-1)) && scp->device->lun)) {
|
||||||
scp->result = DID_BAD_TARGET << 16;
|
scp->result = DID_BAD_TARGET << 16;
|
||||||
free_req(hba, _req);
|
free_req(hba, _req);
|
||||||
goto cmd_done;
|
goto cmd_done;
|
||||||
|
@ -1168,6 +1167,14 @@ static struct device_attribute *hptiop_attrs[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int hptiop_slave_config(struct scsi_device *sdev)
|
||||||
|
{
|
||||||
|
if (sdev->type == TYPE_TAPE)
|
||||||
|
blk_queue_max_hw_sectors(sdev->request_queue, 8192);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct scsi_host_template driver_template = {
|
static struct scsi_host_template driver_template = {
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
.name = driver_name,
|
.name = driver_name,
|
||||||
|
@ -1179,6 +1186,7 @@ static struct scsi_host_template driver_template = {
|
||||||
.use_clustering = ENABLE_CLUSTERING,
|
.use_clustering = ENABLE_CLUSTERING,
|
||||||
.proc_name = driver_name,
|
.proc_name = driver_name,
|
||||||
.shost_attrs = hptiop_attrs,
|
.shost_attrs = hptiop_attrs,
|
||||||
|
.slave_configure = hptiop_slave_config,
|
||||||
.this_id = -1,
|
.this_id = -1,
|
||||||
.change_queue_depth = hptiop_adjust_disk_queue_depth,
|
.change_queue_depth = hptiop_adjust_disk_queue_depth,
|
||||||
};
|
};
|
||||||
|
@ -1323,6 +1331,7 @@ static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
hba = (struct hptiop_hba *)host->hostdata;
|
hba = (struct hptiop_hba *)host->hostdata;
|
||||||
|
memset(hba, 0, sizeof(struct hptiop_hba));
|
||||||
|
|
||||||
hba->ops = iop_ops;
|
hba->ops = iop_ops;
|
||||||
hba->pcidev = pcidev;
|
hba->pcidev = pcidev;
|
||||||
|
@ -1336,7 +1345,7 @@ static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
|
||||||
init_waitqueue_head(&hba->reset_wq);
|
init_waitqueue_head(&hba->reset_wq);
|
||||||
init_waitqueue_head(&hba->ioctl_wq);
|
init_waitqueue_head(&hba->ioctl_wq);
|
||||||
|
|
||||||
host->max_lun = 1;
|
host->max_lun = 128;
|
||||||
host->max_channel = 0;
|
host->max_channel = 0;
|
||||||
host->io_port = 0;
|
host->io_port = 0;
|
||||||
host->n_io_port = 0;
|
host->n_io_port = 0;
|
||||||
|
@ -1428,34 +1437,33 @@ static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
|
||||||
dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
|
dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
|
||||||
|
|
||||||
hba->req_size = req_size;
|
hba->req_size = req_size;
|
||||||
start_virt = dma_alloc_coherent(&pcidev->dev,
|
|
||||||
hba->req_size*hba->max_requests + 0x20,
|
|
||||||
&start_phy, GFP_KERNEL);
|
|
||||||
|
|
||||||
if (!start_virt) {
|
|
||||||
printk(KERN_ERR "scsi%d: fail to alloc request mem\n",
|
|
||||||
hba->host->host_no);
|
|
||||||
goto free_request_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
hba->dma_coherent = start_virt;
|
|
||||||
hba->dma_coherent_handle = start_phy;
|
|
||||||
|
|
||||||
if ((start_phy & 0x1f) != 0) {
|
|
||||||
offset = ((start_phy + 0x1f) & ~0x1f) - start_phy;
|
|
||||||
start_phy += offset;
|
|
||||||
start_virt += offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
hba->req_list = NULL;
|
hba->req_list = NULL;
|
||||||
|
|
||||||
for (i = 0; i < hba->max_requests; i++) {
|
for (i = 0; i < hba->max_requests; i++) {
|
||||||
|
start_virt = dma_alloc_coherent(&pcidev->dev,
|
||||||
|
hba->req_size + 0x20,
|
||||||
|
&start_phy, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!start_virt) {
|
||||||
|
printk(KERN_ERR "scsi%d: fail to alloc request mem\n",
|
||||||
|
hba->host->host_no);
|
||||||
|
goto free_request_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
hba->dma_coherent[i] = start_virt;
|
||||||
|
hba->dma_coherent_handle[i] = start_phy;
|
||||||
|
|
||||||
|
if ((start_phy & 0x1f) != 0) {
|
||||||
|
offset = ((start_phy + 0x1f) & ~0x1f) - start_phy;
|
||||||
|
start_phy += offset;
|
||||||
|
start_virt += offset;
|
||||||
|
}
|
||||||
|
|
||||||
hba->reqs[i].next = NULL;
|
hba->reqs[i].next = NULL;
|
||||||
hba->reqs[i].req_virt = start_virt;
|
hba->reqs[i].req_virt = start_virt;
|
||||||
hba->reqs[i].req_shifted_phy = start_phy >> 5;
|
hba->reqs[i].req_shifted_phy = start_phy >> 5;
|
||||||
hba->reqs[i].index = i;
|
hba->reqs[i].index = i;
|
||||||
free_req(hba, &hba->reqs[i]);
|
free_req(hba, &hba->reqs[i]);
|
||||||
start_virt = (char *)start_virt + hba->req_size;
|
|
||||||
start_phy = start_phy + hba->req_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable Interrupt and start background task */
|
/* Enable Interrupt and start background task */
|
||||||
|
@ -1474,11 +1482,16 @@ static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_request_mem:
|
free_request_mem:
|
||||||
dma_free_coherent(&hba->pcidev->dev,
|
for (i = 0; i < hba->max_requests; i++) {
|
||||||
hba->req_size * hba->max_requests + 0x20,
|
if (hba->dma_coherent[i] && hba->dma_coherent_handle[i])
|
||||||
hba->dma_coherent, hba->dma_coherent_handle);
|
dma_free_coherent(&hba->pcidev->dev,
|
||||||
|
hba->req_size + 0x20,
|
||||||
|
hba->dma_coherent[i],
|
||||||
|
hba->dma_coherent_handle[i]);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
free_request_irq:
|
|
||||||
free_irq(hba->pcidev->irq, hba);
|
free_irq(hba->pcidev->irq, hba);
|
||||||
|
|
||||||
unmap_pci_bar:
|
unmap_pci_bar:
|
||||||
|
@ -1546,6 +1559,7 @@ static void hptiop_remove(struct pci_dev *pcidev)
|
||||||
{
|
{
|
||||||
struct Scsi_Host *host = pci_get_drvdata(pcidev);
|
struct Scsi_Host *host = pci_get_drvdata(pcidev);
|
||||||
struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
|
struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
dprintk("scsi%d: hptiop_remove\n", hba->host->host_no);
|
dprintk("scsi%d: hptiop_remove\n", hba->host->host_no);
|
||||||
|
|
||||||
|
@ -1555,10 +1569,15 @@ static void hptiop_remove(struct pci_dev *pcidev)
|
||||||
|
|
||||||
free_irq(hba->pcidev->irq, hba);
|
free_irq(hba->pcidev->irq, hba);
|
||||||
|
|
||||||
dma_free_coherent(&hba->pcidev->dev,
|
for (i = 0; i < hba->max_requests; i++) {
|
||||||
hba->req_size * hba->max_requests + 0x20,
|
if (hba->dma_coherent[i] && hba->dma_coherent_handle[i])
|
||||||
hba->dma_coherent,
|
dma_free_coherent(&hba->pcidev->dev,
|
||||||
hba->dma_coherent_handle);
|
hba->req_size + 0x20,
|
||||||
|
hba->dma_coherent[i],
|
||||||
|
hba->dma_coherent_handle[i]);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
hba->ops->internal_memfree(hba);
|
hba->ops->internal_memfree(hba);
|
||||||
|
|
||||||
|
@ -1653,6 +1672,14 @@ static struct pci_device_id hptiop_id_table[] = {
|
||||||
{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
|
{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
|
||||||
{ PCI_VDEVICE(TTI, 0x4520), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
{ PCI_VDEVICE(TTI, 0x4520), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
{ PCI_VDEVICE(TTI, 0x4522), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
{ PCI_VDEVICE(TTI, 0x4522), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3610), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3611), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3620), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3622), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3640), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3660), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3680), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
|
{ PCI_VDEVICE(TTI, 0x3690), (kernel_ulong_t)&hptiop_mvfrey_ops },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* HighPoint RR3xxx/4xxx controller driver for Linux
|
* HighPoint RR3xxx/4xxx controller driver for Linux
|
||||||
* Copyright (C) 2006-2012 HighPoint Technologies, Inc. All Rights Reserved.
|
* Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -327,8 +327,8 @@ struct hptiop_hba {
|
||||||
struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
|
struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
|
||||||
|
|
||||||
/* used to free allocated dma area */
|
/* used to free allocated dma area */
|
||||||
void *dma_coherent;
|
void *dma_coherent[HPTIOP_MAX_REQUESTS];
|
||||||
dma_addr_t dma_coherent_handle;
|
dma_addr_t dma_coherent_handle[HPTIOP_MAX_REQUESTS];
|
||||||
|
|
||||||
atomic_t reset_count;
|
atomic_t reset_count;
|
||||||
atomic_t resetting;
|
atomic_t resetting;
|
||||||
|
|
Loading…
Add table
Reference in a new issue