Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f915b7f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull SCSI fixes from James Bottomley:
 "This is nine fixes, seven of which are for the qedi driver (new as of
  4.10) the other two are a use after free in the cxgbi drivers and a
  potential NULL dereference in the rdac device handler"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: libcxgbi: fix skb use after free
  scsi: qedi: Fix endpoint NULL panic during recovery.
  scsi: qedi: set max_fin_rt default value
  scsi: qedi: Set firmware tcp msl timer value.
  scsi: qedi: Fix endpoint NULL panic in qedi_set_path.
  scsi: qedi: Set dma_boundary to 0xfff.
  scsi: qedi: Correctly set firmware max supported BDs.
  scsi: qedi: Fix bad pte call trace when iscsiuio is stopped.
  scsi: scsi_dh_rdac: Use ctlr directly in rdac_failover_get()
parents 55cbdaf6 75b61250
Loading
Loading
Loading
Loading
+18 −7
Original line number Diff line number Diff line
@@ -1873,6 +1873,11 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
	tcp_task->dd_data = tdata;
	task->hdr = NULL;

	if (tdata->skb) {
		kfree_skb(tdata->skb);
		tdata->skb = NULL;
	}

	if (SKB_MAX_HEAD(cdev->skb_tx_rsvd) > (512 * MAX_SKB_FRAGS) &&
	    (opcode == ISCSI_OP_SCSI_DATA_OUT ||
	     (opcode == ISCSI_OP_SCSI_CMD &&
@@ -1890,6 +1895,7 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
		return -ENOMEM;
	}

	skb_get(tdata->skb);
	skb_reserve(tdata->skb, cdev->skb_tx_rsvd);
	task->hdr = (struct iscsi_hdr *)tdata->skb->data;
	task->hdr_max = SKB_TX_ISCSI_PDU_HEADER_MAX; /* BHS + AHS */
@@ -2035,9 +2041,9 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
	unsigned int datalen;
	int err;

	if (!skb) {
	if (!skb || cxgbi_skcb_test_flag(skb, SKCBF_TX_DONE)) {
		log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX,
			"task 0x%p, skb NULL.\n", task);
			"task 0x%p, skb 0x%p\n", task, skb);
		return 0;
	}

@@ -2050,7 +2056,6 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
	}

	datalen = skb->data_len;
	tdata->skb = NULL;

	/* write ppod first if using ofldq to write ppod */
	if (ttinfo->flags & CXGBI_PPOD_INFO_FLAG_VALID) {
@@ -2078,6 +2083,7 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
			pdulen += ISCSI_DIGEST_SIZE;

		task->conn->txdata_octets += pdulen;
		cxgbi_skcb_set_flag(skb, SKCBF_TX_DONE);
		return 0;
	}

@@ -2086,7 +2092,6 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
			"task 0x%p, skb 0x%p, len %u/%u, %d EAGAIN.\n",
			task, skb, skb->len, skb->data_len, err);
		/* reset skb to send when we are called again */
		tdata->skb = skb;
		return err;
	}

@@ -2094,7 +2099,8 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
		"itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n",
		task->itt, skb, skb->len, skb->data_len, err);

	kfree_skb(skb);
	__kfree_skb(tdata->skb);
	tdata->skb = NULL;

	iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err);
	iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED);
@@ -2113,8 +2119,10 @@ void cxgbi_cleanup_task(struct iscsi_task *task)

	tcp_task->dd_data = NULL;
	/*  never reached the xmit task callout */
	if (tdata->skb)
		__kfree_skb(tdata->skb);
	if (tdata->skb) {
		kfree_skb(tdata->skb);
		tdata->skb = NULL;
	}

	task_release_itt(task, task->hdr_itt);
	memset(tdata, 0, sizeof(*tdata));
@@ -2714,6 +2722,9 @@ EXPORT_SYMBOL_GPL(cxgbi_attr_is_visible);
static int __init libcxgbi_init_module(void)
{
	pr_info("%s", version);

	BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, cb) <
		     sizeof(struct cxgbi_skb_cb));
	return 0;
}

+8 −8
Original line number Diff line number Diff line
@@ -195,7 +195,8 @@ struct cxgbi_skb_rx_cb {
};

struct cxgbi_skb_tx_cb {
	void *l2t;
	void *handle;
	void *arp_err_handler;
	struct sk_buff *wr_next;
};

@@ -203,6 +204,7 @@ enum cxgbi_skcb_flags {
	SKCBF_TX_NEED_HDR,	/* packet needs a header */
	SKCBF_TX_MEM_WRITE,     /* memory write */
	SKCBF_TX_FLAG_COMPL,    /* wr completion flag */
	SKCBF_TX_DONE,		/* skb tx done */
	SKCBF_RX_COALESCED,	/* received whole pdu */
	SKCBF_RX_HDR,		/* received pdu header */
	SKCBF_RX_DATA,		/* received pdu payload */
@@ -215,13 +217,13 @@ enum cxgbi_skcb_flags {
};

struct cxgbi_skb_cb {
	unsigned char ulp_mode;
	unsigned long flags;
	unsigned int seq;
	union {
		struct cxgbi_skb_rx_cb rx;
		struct cxgbi_skb_tx_cb tx;
	};
	unsigned char ulp_mode;
	unsigned long flags;
	unsigned int seq;
};

#define CXGBI_SKB_CB(skb)	((struct cxgbi_skb_cb *)&((skb)->cb[0]))
@@ -374,11 +376,9 @@ static inline void cxgbi_sock_enqueue_wr(struct cxgbi_sock *csk,
	cxgbi_skcb_tx_wr_next(skb) = NULL;
	/*
	 * We want to take an extra reference since both us and the driver
	 * need to free the packet before it's really freed. We know there's
	 * just one user currently so we use atomic_set rather than skb_get
	 * to avoid the atomic op.
	 * need to free the packet before it's really freed.
	 */
	atomic_set(&skb->users, 2);
	skb_get(skb);

	if (!csk->wr_pending_head)
		csk->wr_pending_head = skb;
+4 −6
Original line number Diff line number Diff line
@@ -265,18 +265,16 @@ static unsigned int rdac_failover_get(struct rdac_controller *ctlr,
				      struct list_head *list,
				      unsigned char *cdb)
{
	struct scsi_device *sdev = ctlr->ms_sdev;
	struct rdac_dh_data *h = sdev->handler_data;
	struct rdac_mode_common *common;
	unsigned data_size;
	struct rdac_queue_data *qdata;
	u8 *lun_table;

	if (h->ctlr->use_ms10) {
	if (ctlr->use_ms10) {
		struct rdac_pg_expanded *rdac_pg;

		data_size = sizeof(struct rdac_pg_expanded);
		rdac_pg = &h->ctlr->mode_select.expanded;
		rdac_pg = &ctlr->mode_select.expanded;
		memset(rdac_pg, 0, data_size);
		common = &rdac_pg->common;
		rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40;
@@ -288,7 +286,7 @@ static unsigned int rdac_failover_get(struct rdac_controller *ctlr,
		struct rdac_pg_legacy *rdac_pg;

		data_size = sizeof(struct rdac_pg_legacy);
		rdac_pg = &h->ctlr->mode_select.legacy;
		rdac_pg = &ctlr->mode_select.legacy;
		memset(rdac_pg, 0, data_size);
		common = &rdac_pg->common;
		rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
@@ -304,7 +302,7 @@ static unsigned int rdac_failover_get(struct rdac_controller *ctlr,
	}

	/* Prepare the command. */
	if (h->ctlr->use_ms10) {
	if (ctlr->use_ms10) {
		cdb[0] = MODE_SELECT_10;
		cdb[7] = data_size >> 8;
		cdb[8] = data_size & 0xff;
+2 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ struct qedi_endpoint;
#define QEDI_MAX_ISCSI_TASK		4096
#define QEDI_MAX_TASK_NUM		0x0FFF
#define QEDI_MAX_ISCSI_CONNS_PER_HBA	1024
#define QEDI_ISCSI_MAX_BDS_PER_CMD	256	/* Firmware max BDs is 256 */
#define QEDI_ISCSI_MAX_BDS_PER_CMD	255	/* Firmware max BDs is 255 */
#define MAX_OUSTANDING_TASKS_PER_CON	1024

#define QEDI_MAX_BD_LEN		0xffff
@@ -63,6 +63,7 @@ struct qedi_endpoint;
#define QEDI_PAGE_MASK		(~((QEDI_PAGE_SIZE) - 1))

#define QEDI_PAGE_SIZE		4096
#define QEDI_HW_DMA_BOUNDARY	0xfff
#define QEDI_PATH_HANDLE	0xFE0000000UL

struct qedi_uio_ctrl {
+2 −0
Original line number Diff line number Diff line
@@ -1494,6 +1494,8 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
	tmf_hdr = (struct iscsi_tm *)mtask->hdr;
	qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
	ep = qedi_conn->ep;
	if (!ep)
		return -ENODEV;

	tid = qedi_get_task_idx(qedi);
	if (tid == -1)
Loading