SCSI fixes on 20120711
This is a set of three fixes for data corruption (libsas task file), oops causing (NULL in scsi_cmd_to_driver) and driver failure (bnx2i). The oops caused by the NULL in scsi_cmd_to_driver() manifests in scsi_eh_send_cmd() and has been seen by several people now. Signed-off-by: James Bottomley <JBottomley@Parallels.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (GNU/Linux) iQEcBAABAgAGBQJP/S5TAAoJEDeqqVYsXL0MM2EIAMQrBUamIjML5tiKwwD7zZsc GBNPLFD2PJNvzaRweENU+CwbHYc7ipt9FMHC89dlOR4vStKR/7nxUOnH2c/pnogM bbU2JCP0iG4IxU8+kcNBKCmysyu5xdd5kh0NOmwMSQrQVlTdfZz4iFXMPtGrK8H6 vfm5w2Y6HUJEXMgmfohDurvLK3L8GvO7E1tKzEJhmfZZqtqnt5vk++tZKCpqf1lH et29y6Ic+daxHgEBR1gCp11Ywike7e01BJPNnTvpX4XV+E+L7fEDwl2Mb7Rsslh1 L61m4JkR9nDSSH8jD7oqUUlbkx+XTe31M/jj9jiLu0tCxIDgOFFcn6KziM1qINI= =Ir0I -----END PGP SIGNATURE----- Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI fixes from James Bottomley: "This is a set of three fixes for data corruption (libsas task file), oops causing (NULL in scsi_cmd_to_driver) and driver failure (bnx2i). The oops caused by the NULL in scsi_cmd_to_driver() manifests in scsi_eh_send_cmd() and has been seen by several people now. Signed-off-by: James Bottomley <JBottomley@Parallels.com>" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: [SCSI] bnx2i: Removed the reference to the netdev->base_addr [SCSI] libsas: fix taskfile corruption in sas_ata_qc_fill_rtf [SCSI] Fix NULL dereferences in scsi_cmd_to_driver
This commit is contained in:
commit
5f8ebd36f7
7 changed files with 25 additions and 17 deletions
|
@ -201,7 +201,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
|
||||||
|
|
||||||
if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
|
if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
|
||||||
resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
|
resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
|
||||||
memcpy(&resp->ending_fis[0], r+16, 24);
|
memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE);
|
||||||
ts->buf_valid_size = sizeof(*resp);
|
ts->buf_valid_size = sizeof(*resp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -350,6 +350,7 @@ struct bnx2i_hba {
|
||||||
struct pci_dev *pcidev;
|
struct pci_dev *pcidev;
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
void __iomem *regview;
|
void __iomem *regview;
|
||||||
|
resource_size_t reg_base;
|
||||||
|
|
||||||
u32 age;
|
u32 age;
|
||||||
unsigned long cnic_dev_type;
|
unsigned long cnic_dev_type;
|
||||||
|
|
|
@ -2724,7 +2724,6 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
|
||||||
goto arm_cq;
|
goto arm_cq;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_base = ep->hba->netdev->base_addr;
|
|
||||||
if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
|
if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
|
||||||
(ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
|
(ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
|
||||||
config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
|
config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
|
||||||
|
@ -2740,7 +2739,7 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
|
||||||
/* 5709 device in normal node and 5706/5708 devices */
|
/* 5709 device in normal node and 5706/5708 devices */
|
||||||
reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
|
reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
|
||||||
|
|
||||||
ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off,
|
ep->qp.ctx_base = ioremap_nocache(ep->hba->reg_base + reg_off,
|
||||||
MB_KERNEL_CTX_SIZE);
|
MB_KERNEL_CTX_SIZE);
|
||||||
if (!ep->qp.ctx_base)
|
if (!ep->qp.ctx_base)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -811,13 +811,13 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
|
||||||
bnx2i_identify_device(hba);
|
bnx2i_identify_device(hba);
|
||||||
bnx2i_setup_host_queue_size(hba, shost);
|
bnx2i_setup_host_queue_size(hba, shost);
|
||||||
|
|
||||||
|
hba->reg_base = pci_resource_start(hba->pcidev, 0);
|
||||||
if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
|
if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
|
||||||
hba->regview = ioremap_nocache(hba->netdev->base_addr,
|
hba->regview = pci_iomap(hba->pcidev, 0, BNX2_MQ_CONFIG2);
|
||||||
BNX2_MQ_CONFIG2);
|
|
||||||
if (!hba->regview)
|
if (!hba->regview)
|
||||||
goto ioreg_map_err;
|
goto ioreg_map_err;
|
||||||
} else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
|
} else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
|
||||||
hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096);
|
hba->regview = pci_iomap(hba->pcidev, 0, 4096);
|
||||||
if (!hba->regview)
|
if (!hba->regview)
|
||||||
goto ioreg_map_err;
|
goto ioreg_map_err;
|
||||||
}
|
}
|
||||||
|
@ -884,7 +884,7 @@ cid_que_err:
|
||||||
bnx2i_free_mp_bdt(hba);
|
bnx2i_free_mp_bdt(hba);
|
||||||
mp_bdt_mem_err:
|
mp_bdt_mem_err:
|
||||||
if (hba->regview) {
|
if (hba->regview) {
|
||||||
iounmap(hba->regview);
|
pci_iounmap(hba->pcidev, hba->regview);
|
||||||
hba->regview = NULL;
|
hba->regview = NULL;
|
||||||
}
|
}
|
||||||
ioreg_map_err:
|
ioreg_map_err:
|
||||||
|
@ -910,7 +910,7 @@ void bnx2i_free_hba(struct bnx2i_hba *hba)
|
||||||
pci_dev_put(hba->pcidev);
|
pci_dev_put(hba->pcidev);
|
||||||
|
|
||||||
if (hba->regview) {
|
if (hba->regview) {
|
||||||
iounmap(hba->regview);
|
pci_iounmap(hba->pcidev, hba->regview);
|
||||||
hba->regview = NULL;
|
hba->regview = NULL;
|
||||||
}
|
}
|
||||||
bnx2i_free_mp_bdt(hba);
|
bnx2i_free_mp_bdt(hba);
|
||||||
|
|
|
@ -139,12 +139,12 @@ static void sas_ata_task_done(struct sas_task *task)
|
||||||
if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
|
if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
|
||||||
((stat->stat == SAM_STAT_CHECK_CONDITION &&
|
((stat->stat == SAM_STAT_CHECK_CONDITION &&
|
||||||
dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
|
dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
|
||||||
ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
|
memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE);
|
||||||
|
|
||||||
if (!link->sactive) {
|
if (!link->sactive) {
|
||||||
qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
|
qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
|
||||||
} else {
|
} else {
|
||||||
link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command);
|
link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
|
||||||
if (unlikely(link->eh_info.err_mask))
|
if (unlikely(link->eh_info.err_mask))
|
||||||
qc->flags |= ATA_QCFLAG_FAILED;
|
qc->flags |= ATA_QCFLAG_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -161,8 +161,8 @@ static void sas_ata_task_done(struct sas_task *task)
|
||||||
qc->flags |= ATA_QCFLAG_FAILED;
|
qc->flags |= ATA_QCFLAG_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->sata_dev.tf.feature = 0x04; /* status err */
|
dev->sata_dev.fis[3] = 0x04; /* status err */
|
||||||
dev->sata_dev.tf.command = ATA_ERR;
|
dev->sata_dev.fis[2] = ATA_ERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
struct domain_device *dev = qc->ap->private_data;
|
struct domain_device *dev = qc->ap->private_data;
|
||||||
|
|
||||||
memcpy(&qc->result_tf, &dev->sata_dev.tf, sizeof(qc->result_tf));
|
ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,8 @@ enum ata_command_set {
|
||||||
ATAPI_COMMAND_SET = 1,
|
ATAPI_COMMAND_SET = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ATA_RESP_FIS_SIZE 24
|
||||||
|
|
||||||
struct sata_device {
|
struct sata_device {
|
||||||
enum ata_command_set command_set;
|
enum ata_command_set command_set;
|
||||||
struct smp_resp rps_resp; /* report_phy_sata_resp */
|
struct smp_resp rps_resp; /* report_phy_sata_resp */
|
||||||
|
@ -171,7 +173,7 @@ struct sata_device {
|
||||||
|
|
||||||
struct ata_port *ap;
|
struct ata_port *ap;
|
||||||
struct ata_host ata_host;
|
struct ata_host ata_host;
|
||||||
struct ata_taskfile tf;
|
u8 fis[ATA_RESP_FIS_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -537,7 +539,7 @@ enum exec_status {
|
||||||
*/
|
*/
|
||||||
struct ata_task_resp {
|
struct ata_task_resp {
|
||||||
u16 frame_len;
|
u16 frame_len;
|
||||||
u8 ending_fis[24]; /* dev to host or data-in */
|
u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SAS_STATUS_BUF_SIZE 96
|
#define SAS_STATUS_BUF_SIZE 96
|
||||||
|
|
|
@ -134,10 +134,16 @@ struct scsi_cmnd {
|
||||||
|
|
||||||
static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
|
static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
|
||||||
{
|
{
|
||||||
|
struct scsi_driver **sdp;
|
||||||
|
|
||||||
if (!cmd->request->rq_disk)
|
if (!cmd->request->rq_disk)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
|
sdp = (struct scsi_driver **)cmd->request->rq_disk->private_data;
|
||||||
|
if (!sdp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return *sdp;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
|
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
|
||||||
|
|
Loading…
Add table
Reference in a new issue