Commit 7b88ed67 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6:
  [SCSI] mpt: fix disable lsi sas to use msi as default
  [SCSI] fix ABORTED_COMMAND looping forever problem
  [SCSI] sd: revive sd_index_lock
  [SCSI] cxgb3i: update the driver version to 1.0.1
  [SCSI] cxgb3i: Fix spelling errors in documentation
  [SCSI] cxgb3i: added missing include in cxgb3i_ddp.h
  [SCSI] cxgb3i: Outgoing pdus need to observe skb's MAX_SKB_FRAGS
  [SCSI] cxgb3i: added per-task data to track transmit progress
  [SCSI] cxgb3i: transmit work-request fixes
  [SCSI] hptiop: Add new PCI device ID
parents 5b101740 5ce7868e
...@@ -4,7 +4,7 @@ Introduction ...@@ -4,7 +4,7 @@ Introduction
============ ============
The Chelsio T3 ASIC based Adapters (S310, S320, S302, S304, Mezz cards, etc. The Chelsio T3 ASIC based Adapters (S310, S320, S302, S304, Mezz cards, etc.
series of products) supports iSCSI acceleration and iSCSI Direct Data Placement series of products) support iSCSI acceleration and iSCSI Direct Data Placement
(DDP) where the hardware handles the expensive byte touching operations, such (DDP) where the hardware handles the expensive byte touching operations, such
as CRC computation and verification, and direct DMA to the final host memory as CRC computation and verification, and direct DMA to the final host memory
destination: destination:
...@@ -31,9 +31,9 @@ destination: ...@@ -31,9 +31,9 @@ destination:
the TCP segments onto the wire. It handles TCP retransmission if the TCP segments onto the wire. It handles TCP retransmission if
needed. needed.
On receving, S3 h/w recovers the iSCSI PDU by reassembling TCP On receiving, S3 h/w recovers the iSCSI PDU by reassembling TCP
segments, separating the header and data, calculating and verifying segments, separating the header and data, calculating and verifying
the digests, then forwards the header to the host. The payload data, the digests, then forwarding the header to the host. The payload data,
if possible, will be directly placed into the pre-posted host DDP if possible, will be directly placed into the pre-posted host DDP
buffer. Otherwise, the payload data will be sent to the host too. buffer. Otherwise, the payload data will be sent to the host too.
...@@ -68,9 +68,8 @@ The following steps need to be taken to accelerates the open-iscsi initiator: ...@@ -68,9 +68,8 @@ The following steps need to be taken to accelerates the open-iscsi initiator:
sure the ip address is unique in the network. sure the ip address is unique in the network.
3. edit /etc/iscsi/iscsid.conf 3. edit /etc/iscsi/iscsid.conf
The default setting for MaxRecvDataSegmentLength (131072) is too big, The default setting for MaxRecvDataSegmentLength (131072) is too big;
replace "node.conn[0].iscsi.MaxRecvDataSegmentLength" to be a value no replace with a value no bigger than 15360 (for example 8192):
bigger than 15360 (for example 8192):
node.conn[0].iscsi.MaxRecvDataSegmentLength = 8192 node.conn[0].iscsi.MaxRecvDataSegmentLength = 8192
......
...@@ -91,9 +91,9 @@ MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \ ...@@ -91,9 +91,9 @@ MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
controllers (default=0)"); controllers (default=0)");
static int mpt_msi_enable_sas; static int mpt_msi_enable_sas;
module_param(mpt_msi_enable_sas, int, 1); module_param(mpt_msi_enable_sas, int, 0);
MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \ MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
controllers (default=1)"); controllers (default=0)");
static int mpt_channel_mapping; static int mpt_channel_mapping;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/skbuff.h>
#include <scsi/libiscsi_tcp.h> #include <scsi/libiscsi_tcp.h>
/* from cxgb3 LLD */ /* from cxgb3 LLD */
...@@ -113,6 +114,26 @@ struct cxgb3i_endpoint { ...@@ -113,6 +114,26 @@ struct cxgb3i_endpoint {
struct cxgb3i_conn *cconn; struct cxgb3i_conn *cconn;
}; };
/**
* struct cxgb3i_task_data - private iscsi task data
*
* @nr_frags: # of coalesced page frags (from scsi sgl)
* @frags: coalesced page frags (from scsi sgl)
* @skb: tx pdu skb
* @offset: data offset for the next pdu
* @count: max. possible pdu payload
* @sgoffset: offset to the first sg entry for a given offset
*/
#define MAX_PDU_FRAGS ((ULP2_MAX_PDU_PAYLOAD + 512 - 1) / 512)
struct cxgb3i_task_data {
unsigned short nr_frags;
skb_frag_t frags[MAX_PDU_FRAGS];
struct sk_buff *skb;
unsigned int offset;
unsigned int count;
unsigned int sgoffset;
};
int cxgb3i_iscsi_init(void); int cxgb3i_iscsi_init(void);
void cxgb3i_iscsi_cleanup(void); void cxgb3i_iscsi_cleanup(void);
......
...@@ -639,10 +639,11 @@ static int ddp_init(struct t3cdev *tdev) ...@@ -639,10 +639,11 @@ static int ddp_init(struct t3cdev *tdev)
write_unlock(&cxgb3i_ddp_rwlock); write_unlock(&cxgb3i_ddp_rwlock);
ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x " ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x "
"pkt %u,%u.\n", "pkt %u/%u, %u/%u.\n",
ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits, ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits,
ddp->idx_mask, ddp->rsvd_tag_mask, ddp->idx_mask, ddp->rsvd_tag_mask,
ddp->max_txsz, ddp->max_rxsz); ddp->max_txsz, uinfo.max_txsz,
ddp->max_rxsz, uinfo.max_rxsz);
return 0; return 0;
free_ddp_map: free_ddp_map:
...@@ -654,8 +655,8 @@ static int ddp_init(struct t3cdev *tdev) ...@@ -654,8 +655,8 @@ static int ddp_init(struct t3cdev *tdev)
* cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource * cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource
* @tdev: t3cdev adapter * @tdev: t3cdev adapter
* @tformat: tag format * @tformat: tag format
* @txsz: max tx pkt size, filled in by this func. * @txsz: max tx pdu payload size, filled in by this func.
* @rxsz: max rx pkt size, filled in by this func. * @rxsz: max rx pdu payload size, filled in by this func.
* initialize the ddp pagepod manager for a given adapter if needed and * initialize the ddp pagepod manager for a given adapter if needed and
* setup the tag format for a given iscsi entity * setup the tag format for a given iscsi entity
*/ */
...@@ -685,10 +686,12 @@ int cxgb3i_adapter_ddp_init(struct t3cdev *tdev, ...@@ -685,10 +686,12 @@ int cxgb3i_adapter_ddp_init(struct t3cdev *tdev,
tformat->sw_bits, tformat->rsvd_bits, tformat->sw_bits, tformat->rsvd_bits,
tformat->rsvd_shift, tformat->rsvd_mask); tformat->rsvd_shift, tformat->rsvd_mask);
*txsz = ddp->max_txsz; *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
*rxsz = ddp->max_rxsz; ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN);
ddp_log_info("ddp max pkt size: %u, %u.\n", *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
ddp->max_txsz, ddp->max_rxsz); ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN);
ddp_log_info("max payload size: %u/%u, %u/%u.\n",
*txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init); EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init);
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#ifndef __CXGB3I_ULP2_DDP_H__ #ifndef __CXGB3I_ULP2_DDP_H__
#define __CXGB3I_ULP2_DDP_H__ #define __CXGB3I_ULP2_DDP_H__
#include <linux/vmalloc.h>
/** /**
* struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity * struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity
* *
...@@ -85,8 +87,9 @@ struct cxgb3i_ddp_info { ...@@ -85,8 +87,9 @@ struct cxgb3i_ddp_info {
struct sk_buff **gl_skb; struct sk_buff **gl_skb;
}; };
#define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8) */
#define ULP2_MAX_PKT_SIZE 16224 #define ULP2_MAX_PKT_SIZE 16224
#define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_MAX) #define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN)
#define PPOD_PAGES_MAX 4 #define PPOD_PAGES_MAX 4
#define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ #define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include "cxgb3i.h" #include "cxgb3i.h"
#define DRV_MODULE_NAME "cxgb3i" #define DRV_MODULE_NAME "cxgb3i"
#define DRV_MODULE_VERSION "1.0.0" #define DRV_MODULE_VERSION "1.0.1"
#define DRV_MODULE_RELDATE "Jun. 1, 2008" #define DRV_MODULE_RELDATE "Jan. 2009"
static char version[] = static char version[] =
"Chelsio S3xx iSCSI Driver " DRV_MODULE_NAME "Chelsio S3xx iSCSI Driver " DRV_MODULE_NAME
......
...@@ -364,7 +364,8 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth, ...@@ -364,7 +364,8 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,
cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost, cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost,
cmds_max, cmds_max,
sizeof(struct iscsi_tcp_task), sizeof(struct iscsi_tcp_task) +
sizeof(struct cxgb3i_task_data),
initial_cmdsn, ISCSI_MAX_TARGET); initial_cmdsn, ISCSI_MAX_TARGET);
if (!cls_session) if (!cls_session)
return NULL; return NULL;
...@@ -402,17 +403,15 @@ static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn) ...@@ -402,17 +403,15 @@ static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
{ {
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct cxgb3i_conn *cconn = tcp_conn->dd_data; struct cxgb3i_conn *cconn = tcp_conn->dd_data;
unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, unsigned int max = max(512 * MAX_SKB_FRAGS, SKB_TX_HEADROOM);
cconn->hba->snic->tx_max_size -
ISCSI_PDU_NONPAYLOAD_MAX);
max = min(cconn->hba->snic->tx_max_size, max);
if (conn->max_xmit_dlength) if (conn->max_xmit_dlength)
conn->max_xmit_dlength = min_t(unsigned int, conn->max_xmit_dlength = min(conn->max_xmit_dlength, max);
conn->max_xmit_dlength, max);
else else
conn->max_xmit_dlength = max; conn->max_xmit_dlength = max;
align_pdu_size(conn->max_xmit_dlength); align_pdu_size(conn->max_xmit_dlength);
cxgb3i_log_info("conn 0x%p, max xmit %u.\n", cxgb3i_api_debug("conn 0x%p, max xmit %u.\n",
conn, conn->max_xmit_dlength); conn, conn->max_xmit_dlength);
return 0; return 0;
} }
...@@ -427,9 +426,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) ...@@ -427,9 +426,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
{ {
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct cxgb3i_conn *cconn = tcp_conn->dd_data; struct cxgb3i_conn *cconn = tcp_conn->dd_data;
unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, unsigned int max = cconn->hba->snic->rx_max_size;
cconn->hba->snic->rx_max_size -
ISCSI_PDU_NONPAYLOAD_MAX);
align_pdu_size(max); align_pdu_size(max);
if (conn->max_recv_dlength) { if (conn->max_recv_dlength) {
...@@ -439,8 +436,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) ...@@ -439,8 +436,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
conn->max_recv_dlength, max); conn->max_recv_dlength, max);
return -EINVAL; return -EINVAL;
} }
conn->max_recv_dlength = min_t(unsigned int, conn->max_recv_dlength = min(conn->max_recv_dlength, max);
conn->max_recv_dlength, max);
align_pdu_size(conn->max_recv_dlength); align_pdu_size(conn->max_recv_dlength);
} else } else
conn->max_recv_dlength = max; conn->max_recv_dlength = max;
...@@ -844,7 +840,7 @@ static struct scsi_host_template cxgb3i_host_template = { ...@@ -844,7 +840,7 @@ static struct scsi_host_template cxgb3i_host_template = {
.proc_name = "cxgb3i", .proc_name = "cxgb3i",
.queuecommand = iscsi_queuecommand, .queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth, .change_queue_depth = iscsi_change_queue_depth,
.can_queue = 128 * (ISCSI_DEF_XMIT_CMDS_MAX - 1), .can_queue = CXGB3I_SCSI_QDEPTH_DFLT - 1,
.sg_tablesize = SG_ALL, .sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF, .max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
......
This diff is collapsed.
...@@ -178,25 +178,33 @@ void cxgb3i_c3cn_release(struct s3_conn *); ...@@ -178,25 +178,33 @@ void cxgb3i_c3cn_release(struct s3_conn *);
* @flag: see C3CB_FLAG_* below * @flag: see C3CB_FLAG_* below
* @ulp_mode: ULP mode/submode of sk_buff * @ulp_mode: ULP mode/submode of sk_buff
* @seq: tcp sequence number * @seq: tcp sequence number
* @ddigest: pdu data digest
* @pdulen: recovered pdu length
* @wr_data: scratch area for tx wr
*/ */
struct cxgb3_skb_rx_cb {
__u32 ddigest; /* data digest */
__u32 pdulen; /* recovered pdu length */
};
struct cxgb3_skb_tx_cb {
struct sk_buff *wr_next; /* next wr */
};
struct cxgb3_skb_cb { struct cxgb3_skb_cb {
__u8 flags; __u8 flags;
__u8 ulp_mode; __u8 ulp_mode;
__u32 seq; __u32 seq;
__u32 ddigest; union {
__u32 pdulen; struct cxgb3_skb_rx_cb rx;
struct sk_buff *wr_data; struct cxgb3_skb_tx_cb tx;
};
}; };
#define CXGB3_SKB_CB(skb) ((struct cxgb3_skb_cb *)&((skb)->cb[0])) #define CXGB3_SKB_CB(skb) ((struct cxgb3_skb_cb *)&((skb)->cb[0]))
#define skb_flags(skb) (CXGB3_SKB_CB(skb)->flags)
#define skb_ulp_mode(skb) (CXGB3_SKB_CB(skb)->ulp_mode) #define skb_ulp_mode(skb) (CXGB3_SKB_CB(skb)->ulp_mode)
#define skb_ulp_ddigest(skb) (CXGB3_SKB_CB(skb)->ddigest) #define skb_tcp_seq(skb) (CXGB3_SKB_CB(skb)->seq)
#define skb_ulp_pdulen(skb) (CXGB3_SKB_CB(skb)->pdulen) #define skb_rx_ddigest(skb) (CXGB3_SKB_CB(skb)->rx.ddigest)
#define skb_wr_data(skb) (CXGB3_SKB_CB(skb)->wr_data) #define skb_rx_pdulen(skb) (CXGB3_SKB_CB(skb)->rx.pdulen)
#define skb_tx_wr_next(skb) (CXGB3_SKB_CB(skb)->tx.wr_next)
enum c3cb_flags { enum c3cb_flags {
C3CB_FLAG_NEED_HDR = 1 << 0, /* packet needs a TX_DATA_WR header */ C3CB_FLAG_NEED_HDR = 1 << 0, /* packet needs a TX_DATA_WR header */
...@@ -217,6 +225,7 @@ struct sge_opaque_hdr { ...@@ -217,6 +225,7 @@ struct sge_opaque_hdr {
/* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ /* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */
#define TX_HEADER_LEN \ #define TX_HEADER_LEN \
(sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr))
#define SKB_TX_HEADROOM SKB_MAX_HEAD(TX_HEADER_LEN)
/* /*
* get and set private ip for iscsi traffic * get and set private ip for iscsi traffic
......
This diff is collapsed.
...@@ -53,7 +53,7 @@ struct cpl_rx_data_ddp_norss { ...@@ -53,7 +53,7 @@ struct cpl_rx_data_ddp_norss {
#define ULP2_FLAG_DCRC_ERROR 0x20 #define ULP2_FLAG_DCRC_ERROR 0x20
#define ULP2_FLAG_PAD_ERROR 0x40 #define ULP2_FLAG_PAD_ERROR 0x40
void cxgb3i_conn_closing(struct s3_conn *); void cxgb3i_conn_closing(struct s3_conn *c3cn);
void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn);
void cxgb3i_conn_tx_open(struct s3_conn *c3cn); void cxgb3i_conn_tx_open(struct s3_conn *c3cn);
#endif #endif
...@@ -1251,6 +1251,7 @@ static struct pci_device_id hptiop_id_table[] = { ...@@ -1251,6 +1251,7 @@ static struct pci_device_id hptiop_id_table[] = {
{ PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops },
......
...@@ -1040,12 +1040,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -1040,12 +1040,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
action = ACTION_FAIL; action = ACTION_FAIL;
break; break;
case ABORTED_COMMAND: case ABORTED_COMMAND:
action = ACTION_FAIL;
if (sshdr.asc == 0x10) { /* DIF */ if (sshdr.asc == 0x10) { /* DIF */
description = "Target Data Integrity Failure"; description = "Target Data Integrity Failure";
action = ACTION_FAIL;
error = -EILSEQ; error = -EILSEQ;
} else }
action = ACTION_RETRY;
break; break;
case NOT_READY: case NOT_READY:
/* If the device is in the process of becoming /* If the device is in the process of becoming
......
...@@ -107,6 +107,7 @@ static void scsi_disk_release(struct device *cdev); ...@@ -107,6 +107,7 @@ static void scsi_disk_release(struct device *cdev);
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
static void sd_print_result(struct scsi_disk *, int); static void sd_print_result(struct scsi_disk *, int);
static DEFINE_SPINLOCK(sd_index_lock);
static DEFINE_IDA(sd_index_ida); static DEFINE_IDA(sd_index_ida);
/* This semaphore is used to mediate the 0->1 reference get in the /* This semaphore is used to mediate the 0->1 reference get in the
...@@ -1914,7 +1915,9 @@ static int sd_probe(struct device *dev) ...@@ -1914,7 +1915,9 @@ static int sd_probe(struct device *dev)
if (!ida_pre_get(&sd_index_ida, GFP_KERNEL)) if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
goto out_put; goto out_put;
spin_lock(&sd_index_lock);
error = ida_get_new(&sd_index_ida, &index); error = ida_get_new(&sd_index_ida, &index);
spin_unlock(&sd_index_lock);
} while (error == -EAGAIN); } while (error == -EAGAIN);
if (error) if (error)
...@@ -1936,7 +1939,9 @@ static int sd_probe(struct device *dev) ...@@ -1936,7 +1939,9 @@ static int sd_probe(struct device *dev)
return 0; return 0;
out_free_index: out_free_index:
spin_lock(&sd_index_lock);
ida_remove(&sd_index_ida, index); ida_remove(&sd_index_ida, index);
spin_unlock(&sd_index_lock);
out_put: out_put:
put_disk(gd); put_disk(gd);
out_free: out_free:
...@@ -1986,7 +1991,9 @@ static void scsi_disk_release(struct device *dev) ...@@ -1986,7 +1991,9 @@ static void scsi_disk_release(struct device *dev)
struct scsi_disk *sdkp = to_scsi_disk(dev); struct scsi_disk *sdkp = to_scsi_disk(dev);
struct gendisk *disk = sdkp->disk; struct gendisk *disk = sdkp->disk;
spin_lock(&sd_index_lock);
ida_remove(&sd_index_ida, sdkp->index); ida_remove(&sd_index_ida, sdkp->index);
spin_unlock(&sd_index_lock);
disk->private_data = NULL; disk->private_data = NULL;
put_disk(disk); put_disk(disk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment