[PATCH 1/1] scsi: add Synology to 1024 sector blacklist
From: Mike Christie Another day another iSCSI target that cannot handle large IOs. The Synology iSCSI targets report: Block limits VPD page (SBC): Write same no zero (WSNZ): 0 Maximum compare and write length: 0 blocks Optimal transfer length granularity: 0 blocks Maximum transfer length: 0 blocks Optimal transfer length: 0 blocks Maximum prefetch length: 0 blocks Maximum unmap LBA count: 0 Maximum unmap block descriptor count: 0 Optimal unmap granularity: 0 Unmap granularity alignment valid: 0 Unmap granularity alignment: 0 Maximum write same length: 0x0 blocks and the size of the command it can handle seems to depend on how much memory it can allocate at the time. This results in IO errors when handling large IOs. This patch just has us use the old 1024 default sectors for this target by adding it to the scsi blacklist. Reported-by: Ancoron Luciferis Signed-off-by: Mike Christie --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 848c7ca..d2a8bdf 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -227,6 +227,7 @@ static struct { {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, {"Promise", "", NULL, BLIST_SPARSELUN}, {"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024}, + {"SYNOLOGY", "iSCSI Storage", NULL, BLIST_MAX_1024}, {"QUANTUM", "XP34301", "1071", BLIST_NOTQ}, {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, -- 1.8.3.1 -- 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
[PATCH 1/1] SCSI: add 1024 max sectors black list flag
From: Mike Christie This works around a issue with qnap iscsi targets not handling large IOs very well. The target returns: VPD INQUIRY: Block limits page (SBC) Maximum compare and write length: 1 blocks Optimal transfer length granularity: 1 blocks Maximum transfer length: 4294967295 blocks Optimal transfer length: 4294967295 blocks Maximum prefetch, xdread, xdwrite transfer length: 0 blocks Maximum unmap LBA count: 8388607 Maximum unmap block descriptor count: 1 Optimal unmap granularity: 16383 Unmap granularity alignment valid: 0 Unmap granularity alignment: 0 Maximum write same length: 0x blocks Maximum atomic transfer length: 0 Atomic alignment: 0 Atomic transfer length granularity: 0 and it is *sometimes* able to handle at least one IO of size up to 8 MB. We have seen in traces where it will sometimes work, but other times it looks like it fails and it looks like it returns failures if we send multiple large IOs sometimes. Also it looks like it can return 2 different errors. It will sometimes send iscsi reject errors indicating out of resources or it will send invalid cdb illegal requests check conditions. And then when it sends iscsi rejects it does not seem to handle retries when there are command sequence holes, so I could not just add code to try and gracefully handle that error code. The problem is that we do not have a good contact for the company, so we are not able to determine under what conditions it returns which error and why it sometimes works. So, this patch just adds a new black list flag to set targets like this to the old max safe sectors of 1024. The max_hw_sectors changes added in 3.19 caused this regression, so I also ccing stable. Reported-by: Christian Hesse Signed-off-by: Mike Christie Cc: sta...@vger.kernel.org --- drivers/scsi/scsi_devinfo.c | 1 + drivers/scsi/scsi_scan.c| 6 ++ include/scsi/scsi_devinfo.h | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 262ab83..848c7ca 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -226,6 +226,7 @@ static struct { {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, {"Promise", "", NULL, BLIST_SPARSELUN}, + {"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024}, {"QUANTUM", "XP34301", "1071", BLIST_NOTQ}, {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 9c0a520..3e6142f 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -897,6 +897,12 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, */ if (*bflags & BLIST_MAX_512) blk_queue_max_hw_sectors(sdev->request_queue, 512); + /* +* Max 1024 sector transfer length for targets that report incorrect +* max/optimal lengths and relied on the old block layer safe default +*/ + else if (*bflags & BLIST_MAX_1024) + blk_queue_max_hw_sectors(sdev->request_queue, 1024); /* * Some devices may not want to have a start command automatically diff --git a/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h index 183eaab..96e3f56 100644 --- a/include/scsi/scsi_devinfo.h +++ b/include/scsi/scsi_devinfo.h @@ -36,5 +36,6 @@ for sequential scan */ #define BLIST_TRY_VPD_PAGES0x1000 /* Attempt to read VPD pages */ #define BLIST_NO_RSOC 0x2000 /* don't try to issue RSOC */ +#define BLIST_MAX_1024 0x4000 /* maximum 1024 sector cdb length */ #endif -- 1.8.3.1 -- 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
[PATCH 1/1] Sync iscsi fw boot flags
From: Mike Christie iBFT and non-iBFT drivers use the same iscsi boot sysfs interface. For iBFT we just directly export whatever is left by the FW. For non-iBFT drivers we do vendor specific commands to get the info or its just hard coded. This patch syncs up how non-iBFT drivers export boot flag info. The boot flags being defined in this patch match the iBFT flags that indicate if the boot info found was valid and if it was used for to boot with. Signed-off-by: Mike Christie --- drivers/scsi/be2iscsi/be_main.c | 8 +--- drivers/scsi/qla4xxx/ql4_def.h | 1 - drivers/scsi/qla4xxx/ql4_os.c| 6 -- include/linux/iscsi_boot_sysfs.h | 3 +++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index f319340..cd4aff9 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -429,7 +429,8 @@ static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) auth_data.chap.intr_secret); break; case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "2\n"); + rc = sprintf(str, "%u\n", +ISCSI_BOOT_FLAG_VALID | ISCSI_BOOT_FLAG_FW_BOOT_SEL); break; case ISCSI_BOOT_TGT_NIC_ASSOC: rc = sprintf(str, "0\n"); @@ -466,8 +467,9 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "2\n"); - break; + rc = sprintf(str, "%u\n", +ISCSI_BOOT_FLAG_VALID | ISCSI_BOOT_FLAG_FW_BOOT_SEL); + break; case ISCSI_BOOT_ETH_INDEX: rc = sprintf(str, "0\n"); break; diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 8f6d0fb..0380669 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -796,7 +796,6 @@ struct scsi_qla_host { #define CHAP_DMA_BLOCK_SIZE512 struct workqueue_struct *task_wq; unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG]; -#define SYSFS_FLAG_FW_SEL_BOOT 2 struct iscsi_boot_kset *boot_kset; struct ql4_boot_tgt_info boot_tgt; uint16_t phy_port_num; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 6d25879..b63985f 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -5705,7 +5705,8 @@ static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); + rc = sprintf(str, "%d\n", +ISCSI_BOOT_FLAG_VALID | ISCSI_BOOT_FLAG_FW_BOOT_SEL); break; case ISCSI_BOOT_ETH_INDEX: rc = sprintf(str, "0\n"); @@ -5814,7 +5815,8 @@ qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, (char *)&boot_conn->chap.intr_secret); break; case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); + rc = sprintf(str, "%d\n", +ISCSI_BOOT_FLAG_VALID | ISCSI_BOOT_FLAG_FW_BOOT_SEL); break; case ISCSI_BOOT_TGT_NIC_ASSOC: rc = sprintf(str, "0\n"); diff --git a/include/linux/iscsi_boot_sysfs.h b/include/linux/iscsi_boot_sysfs.h index 2a8b165..3f273d6 100644 --- a/include/linux/iscsi_boot_sysfs.h +++ b/include/linux/iscsi_boot_sysfs.h @@ -16,6 +16,9 @@ #ifndef _ISCSI_BOOT_SYSFS_ #define _ISCSI_BOOT_SYSFS_ +#define ISCSI_BOOT_FLAG_VALID 0x1 +#define ISCSI_BOOT_FLAG_FW_BOOT_SEL0x2 + /* * The text attributes names for each of the kobjects. */ -- 1.8.3.1 -- 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
[PATCH 1/1] [PATCH REGRESSION] alua: fix bus detach oops
From: Mike Christie This fixes a regression caused by commit 1d5203284d8acbdfdf9b478d434450b34f338f28 The bug is that the alua detach() callout will try to access the sddev->scsi_dh_data, but we have already set it to NULL. This patch moves the clearing of that field to after detach() is called. It looks like the regression was added during 3.19 development, so it has not been in a released kernel, and so I did not cc stable. Signed-off-by: Mike Christie --- drivers/scsi/device_handler/scsi_dh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 1dba62c..1efebc9 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -136,11 +136,12 @@ static void __detach_handler (struct kref *kref) struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh; struct scsi_device *sdev = scsi_dh_data->sdev; + scsi_dh->detach(sdev); + spin_lock_irq(sdev->request_queue->queue_lock); sdev->scsi_dh_data = NULL; spin_unlock_irq(sdev->request_queue->queue_lock); - scsi_dh->detach(sdev); sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name); module_put(scsi_dh->module); } -- 1.8.3.1 -- 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
[PATCH 2/5] block: add function to issue compare and write
From: Mike Christie This patch adds block layer helpers to send a compare and write request. It differs from requests like discard and write same in that there is a setup function and a issue one. I did this to allow callers add multiple pages with variying offsets and lengths. For the miscompare failure case I am currently having drivers return -ECANCELED, but was not sure if there is a better return code. Signed-off-by: Mike Christie --- block/blk-lib.c | 79 + include/linux/blk_types.h |6 ++- include/linux/blkdev.h|6 +++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/block/blk-lib.c b/block/blk-lib.c index 8411be3..fbb1a91 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -141,6 +141,85 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, } EXPORT_SYMBOL(blkdev_issue_discard); +struct bio_cmp_and_write_data { + int err; + struct completion *wait; +}; + +static void bio_cmp_and_write_end_io(struct bio *bio, int err) +{ + struct bio_cmp_and_write_data *data = bio->bi_private; + + data->err = err; + complete(data->wait); + bio_put(bio); +} + +/** + * blkdev_setup_cmp_and_write - setup a bio for a compare and write operation + * @bdev: blockdev to issue discard for + * @sector:start sector + * @gfp_mask: memory allocation flags (for bio_alloc) + * @nr_pages: number of pages that contain the data to be written and compared + * + * This function should be called to allocate the bio used for + * blkdev_issue_cmp_and_write. The caller should add the pages to be compared + * followed by the write pages using bio_add_pc_page. + */ +struct bio *blkdev_setup_cmp_and_write(struct block_device *bdev, + sector_t sector, gfp_t gfp_mask, + int nr_pages) +{ + struct bio *bio; + + bio = bio_alloc(gfp_mask, nr_pages); + if (!bio) + return NULL; + + bio->bi_iter.bi_sector = sector; + bio->bi_end_io = bio_cmp_and_write_end_io; + bio->bi_bdev = bdev; + return bio; +} +EXPORT_SYMBOL(blkdev_setup_cmp_and_write); + +/** + * blkdev_issue_cmp_and_write - queue a compare and write operation + * @bio: bio prepd with blkdev_setup_cmp_and_write. + * Description: + *Issue a compare and write bio for the sectors in question. For the + *execution of this request the handler should atomically read @nr_sects + *from starting sector @sector, compare them, and if matched write + *@nr_sects to @sector. + * + *If the compare fails and data is not written the handler should return + *-ECANCELED. + */ +int blkdev_issue_cmp_and_write(struct bio *bio) +{ + struct request_queue *q = bdev_get_queue(bio->bi_bdev); + DECLARE_COMPLETION_ONSTACK(wait); + struct bio_cmp_and_write_data data; + unsigned int max_cmp_and_write_sectors; + + max_cmp_and_write_sectors = q->limits.max_cmp_and_write_sectors; + if (max_cmp_and_write_sectors == 0) + return -EOPNOTSUPP; + + if (max_cmp_and_write_sectors < bio->bi_iter.bi_size >> 9) + return -EINVAL; + + data.err = 0; + data.wait = &wait; + bio->bi_private = &data; + + submit_bio(REQ_WRITE | REQ_CMP_AND_WRITE, bio); + /* Wait for bio in-flight */ + wait_for_completion_io(&wait); + return data.err; +} +EXPORT_SYMBOL(blkdev_issue_cmp_and_write); + /** * blkdev_issue_write_same - queue a write same operation * @bdev: target blockdev diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 66c2167..37d1eff 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -160,7 +160,7 @@ enum rq_flag_bits { __REQ_DISCARD, /* request to discard sectors */ __REQ_SECURE, /* secure discard (used with __REQ_DISCARD) */ __REQ_WRITE_SAME, /* write same block many times */ - + __REQ_CMP_AND_WRITE,/* compare data and write if matched */ __REQ_NOIDLE, /* don't anticipate more IO after this one */ __REQ_FUA, /* forced unit access */ __REQ_FLUSH,/* request for cache flush */ @@ -203,14 +203,16 @@ enum rq_flag_bits { #define REQ_PRIO (1ULL << __REQ_PRIO) #define REQ_DISCARD(1ULL << __REQ_DISCARD) #define REQ_WRITE_SAME (1ULL << __REQ_WRITE_SAME) +#define REQ_CMP_AND_WRITE (1ULL << __REQ_CMP_AND_WRITE) #define REQ_NOIDLE (1ULL << __REQ_NOIDLE) + #define REQ_FAILFAST_MASK \ (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) #define REQ_COMMON_MASK \ (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | \ REQ_DISCARD | REQ_WRITE_SAME | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | \ -REQ_SECURE) +REQ_SECURE | REQ_CMP
[PATCH 4/5] lio: use REQ_COMPARE_AND_WRITE if supported
From: Mike Christie This has lio callout to the backing store module if it supports using REQ_COMPARE_AND_WRITE. The backing store would set the device attribute max_compare_and_write_len if it supports using the new request type. If it is not supported then we do the read/cmp/write emulation in the sbc layer like before. Signed-off-by: Mike Christie --- drivers/target/target_core_sbc.c | 21 - drivers/target/target_core_spc.c | 12 ++-- drivers/target/target_core_transport.c |1 + include/target/target_core_backend.h |1 + include/target/target_core_base.h |1 + 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ebe62af..fe0c16a 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -555,6 +555,21 @@ sbc_compare_and_write(struct se_cmd *cmd) return TCM_NO_SENSE; } +static void sbc_setup_compare_and_write(struct se_cmd *cmd, struct sbc_ops *ops, + u32 sectors) +{ + cmd->t_task_nolb = sectors; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB | SCF_COMPARE_AND_WRITE; + + if (cmd->se_dev->dev_attrib.max_compare_and_write_len) { + cmd->execute_cmd = ops->execute_compare_and_write; + } else { + cmd->execute_rw = ops->execute_rw; + cmd->execute_cmd = sbc_compare_and_write; + cmd->transport_complete_callback = compare_and_write_callback; + } +} + static int sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, bool is_write, struct se_cmd *cmd) @@ -842,11 +857,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) */ size = 2 * sbc_get_size(cmd, sectors); cmd->t_task_lba = get_unaligned_be64(&cdb[2]); - cmd->t_task_nolb = sectors; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB | SCF_COMPARE_AND_WRITE; - cmd->execute_rw = ops->execute_rw; - cmd->execute_cmd = sbc_compare_and_write; - cmd->transport_complete_callback = compare_and_write_callback; + sbc_setup_compare_and_write(cmd, ops, sectors); break; case READ_CAPACITY: size = READ_CAP_LEN; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 6cd7222..7db8c22 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -525,8 +525,16 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) /* * Set MAXIMUM COMPARE AND WRITE LENGTH */ - if (dev->dev_attrib.emulate_caw) - buf[5] = 0x01; + if (dev->dev_attrib.emulate_caw) { + if (!dev->dev_attrib.max_compare_and_write_len) + /* +* if backing device does not have special handling +* then sbc will support up to 1 block. +*/ + buf[5] = 0x01; + else + buf[5] = dev->dev_attrib.max_compare_and_write_len; + } /* * Set OPTIMAL TRANSFER LENGTH GRANULARITY diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 9ea0d5f..e7706f9 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1637,6 +1637,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: + case TCM_MISCOMPARE_VERIFY: break; case TCM_OUT_OF_RESOURCES: sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 9adc1bc..06924b1 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -53,6 +53,7 @@ struct sbc_ops { sense_reason_t (*execute_write_same)(struct se_cmd *cmd); sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd); sense_reason_t (*execute_unmap)(struct se_cmd *cmd); + sense_reason_t (*execute_compare_and_write)(struct se_cmd *cmd); }; inttransport_subsystem_register(struct se_subsystem_api *); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 23c518a..bc0a26e 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -697,6 +697,7 @@ struct se_dev_attrib { u32 unmap_granularity; u32 unmap_granularity_alignment; u32 max_write_same_len; + u32 max_compare_and_write_len; u32 max_bytes_per_io; st
[PATCH 0/5] block/scsi/lio support for COMPARE_AND_WRITE
The following patches implement the SCSI command COMPARE_AND_WRITE as a new bio/request type REQ_CMP_AND_WRITE. COMPARE_AND_WRITE is defined in the SCSI SBC (SCSI block command) specs as: The COMPARE AND WRITE command requests that the device server perform the following as an uninterrupted series of actions: 1) perform the following operations: A) read the specified logical blocks; and B) transfer the specified number of logical blocks from the Data-Out Buffer (i.e., the verify instance of the data is transferred from the Data-Out Buffer); 2) compare the data read from the specified logical blocks with the verify instance of the data; and 3) If the compared data matches, then perform the following operations: 1) transfer the specified number of logical blocks from the Data-Out Buffer (i.e., the write instance of the data transferred from the Data-Out Buffer); and 2) write those logical blocks. The most command use of this command today is in VMware ESX where it is used for locking. See http://blogs.vmware.com/vsphere/2012/05/vmfs-locking-uncovered.html [in ESX is it is called ATS (atomic test and set)] for more VMware info. Linux fits into this use, because its SCSI target layer (LIO) is commonly used as storage for ESX VMs. Currently, to support this command in LIO we emulate it by taking a lock, doing a read, comparing it, then doing a write. The problem this patchset tries to solve is that in many cases it is more efficient to pass the one COMPARE_AND_REQUEST request directly to the device where it might have optimized locking and also will require fewer requests to/from the target and backing storage device. I am also bugging the ceph-devel list, because I am working on LIO + ceph support. I am interested in using ceph's rbd device for the backing storage for LIO, and I was thinking this request could be implemented similar to how REQ_DISCARD (unmap/trim) is going to be, and I wanted to get some early feedback. I know the scsi layer better, so I have only added support in sd in this patchset. The following patches were made over the target-pending for-next branch but also apply to Linus's tree. -- 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
[PATCH 3/5] scsi: add support for COMPARE_AND_WRITE
From: Mike Christie This patch adds support to detect if a device supports COMPARE_AND_WRITE and execute REQ_COMPARE_AND_WRITE commands. Signed-off-by: Mike Christie --- drivers/scsi/scsi_lib.c |7 + drivers/scsi/sd.c | 63 +++ drivers/scsi/sd.h |1 + 3 files changed, 71 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d837dc1..9e7ba4f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1021,6 +1021,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) /* See SSC3rXX or current. */ action = ACTION_FAIL; break; + case MISCOMPARE: + /* miscompare during verify */ + if (sshdr.asc == 0x1d) + /* TODO: better error code to use ??? */ + error = -ECANCELED; + action = ACTION_FAIL; + break; default: action = ACTION_FAIL; break; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2c2041c..d1fa4ef 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -477,6 +477,16 @@ max_write_same_blocks_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(max_write_same_blocks); +static ssize_t +max_cmp_and_write_blocks_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", sdkp->max_cmp_and_write_blocks); +} +static DEVICE_ATTR_RO(max_cmp_and_write_blocks); + static struct attribute *sd_disk_attrs[] = { &dev_attr_cache_type.attr, &dev_attr_FUA.attr, @@ -488,6 +498,7 @@ static struct attribute *sd_disk_attrs[] = { &dev_attr_thin_provisioning.attr, &dev_attr_provisioning_mode.attr, &dev_attr_max_write_same_blocks.attr, + &dev_attr_max_cmp_and_write_blocks.attr, &dev_attr_max_medium_access_timeouts.attr, NULL, }; @@ -635,6 +646,54 @@ static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) scsi_set_prot_type(scmd, dif); } +static void sd_config_cmp_and_write(struct scsi_disk *sdkp) +{ + if (sdkp->max_cmp_and_write_blocks > sdkp->max_xfer_blocks) { + /* Invalid settings returned. Do not try to support for now */ + blk_queue_max_cmp_and_write_sectors(sdkp->disk->queue, 0); + return; + } + + /* +* mult by 2, because the block layer wants the total number of +* sectors that will be put in bios and transferred. +*/ + blk_queue_max_cmp_and_write_sectors(sdkp->disk->queue, + 2 * sdkp->max_cmp_and_write_blocks * + (sdkp->device->sector_size >> 9)); +} + +/** + * sd_setup_cmp_and_write_cmnd - compare and write data + * @cmd: scsi_cmnd to prepare + **/ +static int sd_setup_cmd_and_write_cmd(struct scsi_cmnd *cmd) +{ + struct request *rq = cmd->request; + struct scsi_device *sdp = cmd->device; + sector_t sector = blk_rq_pos(rq); + unsigned int nr_sectors = blk_rq_sectors(rq); + + sector >>= ilog2(sdp->sector_size) - 9; + nr_sectors >>= ilog2(sdp->sector_size) - 9; + + cmd->cmnd[0] = COMPARE_AND_WRITE; + put_unaligned_be64(sector, &cmd->cmnd[2]); + /* +* rq/bio contains total data to transfer, but the nr LBAs field +* is only the data to be compared/written in each step of the +* operation. +*/ + cmd->cmnd[13] = nr_sectors >> 1; + /* TODO - wrprotect and FUA and DPO flags */ + + cmd->transfersize = sdp->sector_size; + cmd->allowed = SD_MAX_RETRIES; + rq->timeout = SD_TIMEOUT; + + return scsi_init_io(cmd, GFP_ATOMIC); +} + static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) { struct request_queue *q = sdkp->disk->queue; @@ -1134,6 +1193,8 @@ static int sd_init_command(struct scsi_cmnd *cmd) return sd_setup_write_same_cmnd(cmd); else if (rq->cmd_flags & REQ_FLUSH) return sd_setup_flush_cmnd(cmd); + else if (rq->cmd_flags & REQ_CMP_AND_WRITE) + return sd_setup_cmd_and_write_cmd(cmd); else return sd_setup_read_write_cmnd(cmd); } @@ -2596,6 +2657,8 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) get_unaligned_be16(&buffer[6]) * sector_sz); blk_queue_io_opt(sdkp->disk->queue, get_unaligned_be32(&buffer[12]) * sector_sz); + sdkp->max_cmp_and_write_blocks = buffer[5]; + sd_config_cmp_and_write(sdkp); if (buffer[3] == 0x3c) { uns
[PATCH 1/5] block: set the nr of sectors a dev can compare and write atomically
From: Mike Christie This adds blk settings helpers to allow drivers to tell the block layer how many sectors it can process in a COMPARE_AND_WRITE/ATS request. Signed-off-by: Mike Christie --- block/blk-settings.c | 20 block/blk-sysfs.c | 11 +++ include/linux/blkdev.h |3 +++ 3 files changed, 34 insertions(+), 0 deletions(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index f1a1795..b33cf1c 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -114,6 +114,7 @@ void blk_set_default_limits(struct queue_limits *lim) lim->max_segment_size = BLK_MAX_SEGMENT_SIZE; lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS; lim->chunk_sectors = 0; + lim->max_cmp_and_write_sectors = 0; lim->max_write_same_sectors = 0; lim->max_discard_sectors = 0; lim->discard_granularity = 0; @@ -147,6 +148,7 @@ void blk_set_stacking_limits(struct queue_limits *lim) lim->max_hw_sectors = UINT_MAX; lim->max_segment_size = UINT_MAX; lim->max_sectors = UINT_MAX; + lim->max_cmp_and_write_sectors = UINT_MAX; lim->max_write_same_sectors = UINT_MAX; } EXPORT_SYMBOL(blk_set_stacking_limits); @@ -298,6 +300,22 @@ void blk_queue_chunk_sectors(struct request_queue *q, unsigned int chunk_sectors EXPORT_SYMBOL(blk_queue_chunk_sectors); /** + * blk_queue_max_cmp_and_write_sectors - set max sectors for a single request + * @q: the request queue for the device + * @max_cmp_and_write_sectors: maximum number of 512b sectors to cmp and write + * + * Description: + *This sets the total number of sectors that the device can process + *in a compare and write operation. + **/ +void blk_queue_max_cmp_and_write_sectors(struct request_queue *q, +unsigned int max_cmp_and_write_sectors) +{ + q->limits.max_cmp_and_write_sectors = max_cmp_and_write_sectors; +} +EXPORT_SYMBOL(blk_queue_max_cmp_and_write_sectors); + +/** * blk_queue_max_discard_sectors - set max sectors for a single discard * @q: the request queue for the device * @max_discard_sectors: maximum number of sectors to discard @@ -548,6 +566,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); t->max_write_same_sectors = min(t->max_write_same_sectors, b->max_write_same_sectors); + t->max_cmp_and_write_sectors = min(t->max_cmp_and_write_sectors, + b->max_cmp_and_write_sectors); t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 17f5c84..c546400 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -161,6 +161,11 @@ static ssize_t queue_write_same_max_show(struct request_queue *q, char *page) (unsigned long long)q->limits.max_write_same_sectors << 9); } +static ssize_t queue_cmp_and_write_max_show(struct request_queue *q, char *page) +{ + return sprintf(page, "%llu\n", + (unsigned long long)q->limits.max_cmp_and_write_sectors << 9); +} static ssize_t queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) @@ -374,6 +379,11 @@ static struct queue_sysfs_entry queue_write_same_max_entry = { .show = queue_write_same_max_show, }; +static struct queue_sysfs_entry queue_cmp_and_write_max_entry = { + .attr = {.name = "cmp_and_write_max_bytes", .mode = S_IRUGO }, + .show = queue_cmp_and_write_max_show, +}; + static struct queue_sysfs_entry queue_nonrot_entry = { .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR }, .show = queue_show_nonrot, @@ -422,6 +432,7 @@ static struct attribute *default_attrs[] = { &queue_discard_max_entry.attr, &queue_discard_zeroes_data_entry.attr, &queue_write_same_max_entry.attr, + &queue_cmp_and_write_max_entry.attr, &queue_nonrot_entry.attr, &queue_nomerges_entry.attr, &queue_rq_affinity_entry.attr, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 518b465..6d03206 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -290,6 +290,7 @@ struct queue_limits { unsigned intio_opt; unsigned intmax_discard_sectors; unsigned intmax_write_same_sectors; + unsigned intmax_cmp_and_write_sectors; unsigned intdiscard_granularity; unsigned intdiscard_alignment; @@ -1009,6 +1010,8 @@ extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_segments(struct request_queue *, unsigned short);
[PATCH 5/5] lio iblock: add support for REQ_CMP_AND_WRITE
From: Mike Christie This patch has the iblock backing store use blkdev_issue_cmp_and_write if the backing store device/queue supports it. Signed-off-by: Mike Christie --- drivers/target/target_core_iblock.c | 85 --- 1 files changed, 68 insertions(+), 17 deletions(-) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 7e6b857..cac928a 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -153,6 +153,11 @@ static int iblock_configure_device(struct se_device *dev) */ dev->dev_attrib.max_write_same_len = 0x; + /* convert from linux block layer 512 byte sector to our block size */ + dev->dev_attrib.max_compare_and_write_len = + (q->limits.max_cmp_and_write_sectors << IBLOCK_LBA_SHIFT) / + dev->dev_attrib.hw_block_size; + if (blk_queue_nonrot(q)) dev->dev_attrib.is_nonrot = 1; @@ -413,6 +418,67 @@ iblock_execute_sync_cache(struct se_cmd *cmd) return 0; } +/* + * Convert the blocksize advertised to the initiator to the 512 byte + * units unconditionally used by the Linux block layer. + */ +static int iblock_get_lba_shift(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + if (dev->dev_attrib.block_size == 4096) + return 3; + else if (dev->dev_attrib.block_size == 2048) + return 2; + else if (dev->dev_attrib.block_size == 1024) + return 1; + else + return 0; +} + +static sense_reason_t +iblock_execute_compare_and_write(struct se_cmd *cmd) +{ + struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; + int ret, i = 0; + sector_t block_lba; + struct scatterlist *sg; + struct bio *bio; + + block_lba = cmd->t_task_lba << iblock_get_lba_shift(cmd); + + /* assumes SGLs are PAGE_SIZE */ + bio = blkdev_setup_cmp_and_write(bdev, block_lba, GFP_KERNEL, +cmd->t_data_nents); + if (!bio) { + pr_err("blkdev_setup_cmp_and_write() failed\n"); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { + ret = bio_add_pc_page(bdev_get_queue(bdev), bio, sg_page(sg), + sg->length, sg->offset); + if (ret != sg->length) { + bio_put(bio); + pr_err("bio_add_pc_page() failed\n"); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + } + + ret = blkdev_issue_cmp_and_write(bio); + if (ret == -ECANCELED) { + pr_warn("Target/%s: Send MISCOMPARE check condition and sense\n", + cmd->se_dev->transport->name); + return TCM_MISCOMPARE_VERIFY; + } else if (ret < 0) { + pr_err("blkdev_issue_cmp_and_write() failed: %d\n", ret); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + target_complete_cmd(cmd, GOOD); + return 0; +} + static sense_reason_t iblock_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) @@ -701,23 +767,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, rw = READ; } - /* -* Convert the blocksize advertised to the initiator to the 512 byte -* units unconditionally used by the Linux block layer. -*/ - if (dev->dev_attrib.block_size == 4096) - block_lba = (cmd->t_task_lba << 3); - else if (dev->dev_attrib.block_size == 2048) - block_lba = (cmd->t_task_lba << 2); - else if (dev->dev_attrib.block_size == 1024) - block_lba = (cmd->t_task_lba << 1); - else if (dev->dev_attrib.block_size == 512) - block_lba = cmd->t_task_lba; - else { - pr_err("Unsupported SCSI -> BLOCK LBA conversion:" - " %u\n", dev->dev_attrib.block_size); - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } + block_lba = cmd->t_task_lba << iblock_get_lba_shift(cmd); ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); if (!ibr) @@ -841,6 +891,7 @@ static struct sbc_ops iblock_sbc_ops = { .execute_write_same = iblock_execute_write_same, .execute_write_same_unmap = iblock_execute_write_same_unmap, .execute_unmap = iblock_execute_unmap, + .execute_compare_and_write = iblock_execute_compare_and_write, }; static sense_reason_t -- 1.7.1 -- 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
[PATCH 0/2] iscsi patches for 3.18
A couple patches made over the scsi-queue drivers-for-3.18 branch. They just fix a possible bug with be2iscsi that Dan reported and also export the iscsi port being used. -- 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
[PATCH 1/2] be2iscsi: check ip buffer before copying
From: Mike Christie Dan Carpenter found a issue where be2iscsi would copy the ip from userspace to the driver buffer before checking the len of the data being copied: http://marc.info/?l=linux-scsi&m=140982651504251&w=2 This patch just has us only copy what we the driver buffer can support. Tested-by: John Soni Jose Signed-off-by: Mike Christie --- drivers/scsi/be2iscsi/be_mgmt.c | 13 - 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 8478506..681d4e8 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -943,17 +943,20 @@ mgmt_static_ip_modify(struct beiscsi_hba *phba, if (ip_action == IP_ACTION_ADD) { memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value, - ip_param->len); + sizeof(req->ip_params.ip_record.ip_addr.addr)); if (subnet_param) memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - subnet_param->value, subnet_param->len); + subnet_param->value, + sizeof(req->ip_params.ip_record.ip_addr.subnet_mask)); } else { memcpy(req->ip_params.ip_record.ip_addr.addr, - if_info->ip_addr.addr, ip_param->len); + if_info->ip_addr.addr, + sizeof(req->ip_params.ip_record.ip_addr.addr)); memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - if_info->ip_addr.subnet_mask, ip_param->len); + if_info->ip_addr.subnet_mask, + sizeof(req->ip_params.ip_record.ip_addr.subnet_mask)); } rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); @@ -981,7 +984,7 @@ static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr, req->action = gtway_action; req->ip_addr.ip_type = BE2_IPV4; - memcpy(req->ip_addr.addr, gt_addr, param_len); + memcpy(req->ip_addr.addr, gt_addr, sizeof(req->ip_addr.addr)); return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); } -- 1.7.1 -- 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
[PATCH 2/2] iscsi_tcp: export port being used
From: Mike Christie This just has iscsi_tcp support ISCSI_PARAM_LOCAL_PORT which exports the local port being used by the iscsi connection. Signed-off-by: Mike Christie --- drivers/scsi/iscsi_tcp.c | 10 -- drivers/scsi/libiscsi.c |1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index a669f2d..427af0f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -726,13 +726,18 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, switch(param) { case ISCSI_PARAM_CONN_PORT: case ISCSI_PARAM_CONN_ADDRESS: + case ISCSI_PARAM_LOCAL_PORT: spin_lock_bh(&conn->session->frwd_lock); if (!tcp_sw_conn || !tcp_sw_conn->sock) { spin_unlock_bh(&conn->session->frwd_lock); return -ENOTCONN; } - rc = kernel_getpeername(tcp_sw_conn->sock, - (struct sockaddr *)&addr, &len); + if (param == ISCSI_PARAM_LOCAL_PORT) + rc = kernel_getsockname(tcp_sw_conn->sock, + (struct sockaddr *)&addr, &len); + else + rc = kernel_getpeername(tcp_sw_conn->sock, + (struct sockaddr *)&addr, &len); spin_unlock_bh(&conn->session->frwd_lock); if (rc) return rc; @@ -895,6 +900,7 @@ static umode_t iscsi_sw_tcp_attr_is_visible(int param_type, int param) case ISCSI_PARAM_DATADGST_EN: case ISCSI_PARAM_CONN_ADDRESS: case ISCSI_PARAM_CONN_PORT: + case ISCSI_PARAM_LOCAL_PORT: case ISCSI_PARAM_EXP_STATSN: case ISCSI_PARAM_PERSISTENT_ADDRESS: case ISCSI_PARAM_PERSISTENT_PORT: diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 191b597..0d8bc6c 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -3505,6 +3505,7 @@ int iscsi_conn_get_addr_param(struct sockaddr_storage *addr, len = sprintf(buf, "%pI6\n", &sin6->sin6_addr); break; case ISCSI_PARAM_CONN_PORT: + case ISCSI_PARAM_LOCAL_PORT: if (sin) len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port)); else -- 1.7.1 -- 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
[PATCH 1/1] libiscsi: fix potential buffer overrun in __iscsi_conn_send_pdu
From: Mike Christie This patches fixes a potential buffer overrun in __iscsi_conn_send_pdu. This function is used by iscsi drivers and userspace to send iscsi PDUs/ commands. For login commands, we have a set buffer size. For all other commands we do not support data buffers. This was reported by Dan Carpenter here: http://www.spinics.net/lists/linux-scsi/msg66838.html Reported-by: Dan Carpenter Signed-off-by: Mike Christie --- drivers/scsi/libiscsi.c | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index ea025e4..191b597 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -717,11 +717,21 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, return NULL; } + if (data_size > ISCSI_DEF_MAX_RECV_SEG_LEN) { + iscsi_conn_printk(KERN_ERR, conn, "Invalid buffer len of %u for login task. Max len is %u\n", data_size, ISCSI_DEF_MAX_RECV_SEG_LEN); + return NULL; + } + task = conn->login_task; } else { if (session->state != ISCSI_STATE_LOGGED_IN) return NULL; + if (data_size != 0) { + iscsi_conn_printk(KERN_ERR, conn, "Can not send data buffer of len %u for op 0x%x\n", data_size, opcode); + return NULL; + } + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); -- 1.7.1 -- 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
[PATCH 1/1] iscsi class: Fix freeing of skb in get host error path
From: Mike Christie If get_host_stats failes we are using kfree to free the skb. We should be using kfree_skb. This patch was made over Christoph's scsi-queue drivers-for-3.17 branch. Signed-off-by: Mike Christie --- drivers/scsi/scsi_transport_iscsi.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 534d3fb..67d43e3 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3468,7 +3468,7 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) err = transport->get_host_stats(shost, buf, host_stats_size); if (err) { - kfree(skbhost_stats); + kfree_skb(skbhost_stats); goto exit_host_stats; } -- 1.7.1 -- 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
[PATCH 3/4] iscsi class: fix get_host_stats return code when not supported
From: Mike Christie When the get_host_stats call was not supported we were returing EINVAL. This has us return ENOSYS, because for software iscsi drivers where there is no host it is ok to not have this callout. Signed-off-by: Mike Christie --- drivers/scsi/scsi_transport_iscsi.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 14bfa53..534d3fb 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3429,7 +3429,7 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) char *buf; if (!transport->get_host_stats) - return -EINVAL; + return -ENOSYS; priv = iscsi_if_transport_lookup(transport); if (!priv) -- 1.7.1 -- 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
[PATCH 4/4] libiscsi: return new error code when nop times out
From: Mike Christie When a iscsi nop as ping timedout we were failing with the common connection error code, ISCSI_ERR_CONN_FAILED. This patch adds a new error code for this problem so can properly track/distinguish in userspace. Signed-off-by: Mike Christie --- drivers/scsi/libiscsi.c |2 +- include/scsi/iscsi_if.h |1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index f2db82b..b0813fd 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2097,7 +2097,7 @@ static void iscsi_check_transport_timeouts(unsigned long data) conn->ping_timeout, conn->recv_timeout, last_recv, conn->last_ping, jiffies); spin_unlock(&session->frwd_lock); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + iscsi_conn_failure(conn, ISCSI_ERR_NOP_TIMEDOUT); return; } diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index fd0421c..95ed942 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -527,6 +527,7 @@ enum iscsi_err { ISCSI_ERR_XMIT_FAILED = ISCSI_ERR_BASE + 19, ISCSI_ERR_TCP_CONN_CLOSE= ISCSI_ERR_BASE + 20, ISCSI_ERR_SCSI_EH_SESSION_RST = ISCSI_ERR_BASE + 21, + ISCSI_ERR_NOP_TIMEDOUT = ISCSI_ERR_BASE + 22, }; /* -- 1.7.1 -- 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
[PATCH 1/4] iscsi class: fix get_host_stats error handling
From: Mike Christie iscsi_get_host_stats was dropping the error code returned by drivers like qla4xxx. Signed-off-by: Mike Christie --- drivers/scsi/scsi_transport_iscsi.c |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b481e62..14bfa53 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3467,6 +3467,10 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) memset(buf, 0, host_stats_size); err = transport->get_host_stats(shost, buf, host_stats_size); + if (err) { + kfree(skbhost_stats); + goto exit_host_stats; + } actual_size = nlmsg_total_size(sizeof(*ev) + host_stats_size); skb_trim(skbhost_stats, NLMSG_ALIGN(actual_size)); -- 1.7.1 -- 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
[PATCH 2/4] qla4xxx: fix get_host_stats error propagation
From: Mike Christie qla4xxx was not always returning -EXYZ error codes when qla4xxx_get_host_stats failed. Signed-off-by: Mike Christie Acked-by: Vikas Chaudhary --- drivers/scsi/qla4xxx/ql4_os.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index c5d9564..b79b48c 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1050,6 +1050,7 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len) if (!ql_iscsi_stats) { ql4_printk(KERN_ERR, ha, "Unable to allocate memory for iscsi stats\n"); + ret = -ENOMEM; goto exit_host_stats; } @@ -1058,6 +1059,7 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len) if (ret != QLA_SUCCESS) { ql4_printk(KERN_ERR, ha, "Unable to retrieve iscsi stats\n"); + ret = -EIO; goto exit_host_stats; } host_stats->mactx_frames = le64_to_cpu(ql_iscsi_stats->mac_tx_frames); -- 1.7.1 -- 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
[PATCH 0/4] iscsi: iscsi changes for 3.17
The following patches were made over Chrisoph's scsi-queue drivers-for-3.17 branch. They are some fixes to the get_host_stats code and new error code for when a iscsi ping times out. Note for applying/merging: The patches also apply over James's scsi misc branch, but that branch is missing some patches that Chrisoph has picked up. -- 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
[PATCH 2/2] bnx2i, be2iscsi: fix custom stats length
From: Mike Christie The custom stats is an array with custom_length indicating the length of the array. This patch fixes bnx2i and be2iscsi's setting of the custom stats length. They both just have the one, eh_abort_cnt, so that should be in the first entry of the custom array and custom_length should then be one. Reported-by: Rickard Strandqvist Signed-off-by: Mike Christie Acked-by: Eddie Wai --- drivers/scsi/be2iscsi/be_iscsi.c |2 +- drivers/scsi/bnx2i/bnx2i_iscsi.c |7 +++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index fd284ff..8616281 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -914,7 +914,7 @@ void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, stats->r2t_pdus = conn->r2t_pdus_cnt; stats->digest_err = 0; stats->timeout_err = 0; - stats->custom_length = 0; + stats->custom_length = 1; strcpy(stats->custom[0].desc, "eh_abort_cnt"); stats->custom[0].value = conn->eh_abort_cnt; } diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 166543f..9bd9b81 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1643,12 +1643,11 @@ static void bnx2i_conn_get_stats(struct iscsi_cls_conn *cls_conn, stats->r2t_pdus = conn->r2t_pdus_cnt; stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->custom_length = 3; - strcpy(stats->custom[2].desc, "eh_abort_cnt"); - stats->custom[2].value = conn->eh_abort_cnt; stats->digest_err = 0; stats->timeout_err = 0; - stats->custom_length = 0; + strcpy(stats->custom[0].desc, "eh_abort_cnt"); + stats->custom[0].value = conn->eh_abort_cnt; + stats->custom_length = 1; } -- 1.7.1 -- 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
[PATCH 1/2] iscsi: kill redundant casts
From: Nick Black' via open-iscsi Remove two redundant casts from char * to char *. Signed-off-by: Nick Black Signed-off-by: Mike Christie --- drivers/scsi/scsi_transport_iscsi.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 126bf26..b481e62 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3059,7 +3059,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh) evchap->u.get_chap.host_no = ev->u.get_chap.host_no; evchap->u.get_chap.chap_tbl_idx = ev->u.get_chap.chap_tbl_idx; evchap->u.get_chap.num_entries = ev->u.get_chap.num_entries; - buf = (char *) ((char *)evchap + sizeof(*evchap)); + buf = (char *)evchap + sizeof(*evchap); memset(buf, 0, chap_buf_size); err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx, @@ -3463,7 +3463,7 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) evhost_stats->type = nlh->nlmsg_type; evhost_stats->u.get_host_stats.host_no = ev->u.get_host_stats.host_no; - buf = (char *)((char *)evhost_stats + sizeof(*evhost_stats)); + buf = (char *)evhost_stats + sizeof(*evhost_stats); memset(buf, 0, host_stats_size); err = transport->get_host_stats(shost, buf, host_stats_size); -- 1.7.1 -- 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
[PATCH 0/2] iscsi changes for 3.17
This patchset has iscsi changes built over Christoph's scsi-queue for-3.17 branch. The patches also apply to James's misc tree. They are not critical bug fixes, so they are best for 3.17 feature window. -- 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
[PATCH 5/6] iscsi_boot_sysfs: Fix a memory leak in iscsi_boot_destroy_kset()
From: Ethan Zhao Load and unload iscsi_ibft module will cause kernel memory leak, fix it in scsi/iscsi_boot_sysfs.c iscsi_boot_destroy_kset(). Signed-off-by: Ethan Zhao Signed-off-by: Mike Christie --- drivers/scsi/iscsi_boot_sysfs.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index 14c1c8f..680bf6f 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -490,5 +490,6 @@ void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) iscsi_boot_remove_kobj(boot_kobj); kset_unregister(boot_kset->kset); + kfree(boot_kset); } EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); -- 1.7.1 -- 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
[PATCH 4/6] be2iscsi: fix lun test in device reset callout
From: Mike Christie We want to be checking the scsi_cmnd's lun against the possible tasks in the driver. Current check tests task against itself which was useless. Signed-off-by: Mike Christie --- drivers/scsi/be2iscsi/be_main.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 8d82f2c..bc77a6f 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -325,7 +325,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE) continue; - if (abrt_task->sc->device->lun != abrt_task->sc->device->lun) + if (sc->device->lun != abrt_task->sc->device->lun) continue; /* Invalidate WRB Posted for this Task */ -- 1.7.1 -- 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
[PATCH 1/6] SCSI/libiscsi: Restructure iscsi_tcp r2t response logic
From: Shlomo Pongratz Restructure the iscsi_tcp_r2t_rsp routine in order to avoid allocating r2t from r2tpool.queue and returning it back in case the parameters rhdr->data_length and or rhdr->data_offset prohibit the requing. Since the values of these parameters are known prior to the allocation, we can pre-check and thus avoid futile allocations. Signed-off-by: Shlomo Pongratz Signed-off-by: Or Gerlitz Signed-off-by: Mike Christie --- drivers/scsi/libiscsi_tcp.c | 43 ++- 1 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 1d58d53..7f59073 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -529,6 +529,8 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; struct iscsi_r2t_info *r2t; int r2tsn = be32_to_cpu(rhdr->r2tsn); + u32 data_length; + u32 data_offset; int rc; if (tcp_conn->in.datalen) { @@ -554,40 +556,39 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) return 0; } - rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); - if (!rc) { - iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. " - "Target has sent more R2Ts than it " - "negotiated for or driver has leaked.\n"); - return ISCSI_ERR_PROTO; - } - - r2t->exp_statsn = rhdr->statsn; - r2t->data_length = be32_to_cpu(rhdr->data_length); - if (r2t->data_length == 0) { + data_length = be32_to_cpu(rhdr->data_length); + if (data_length == 0) { iscsi_conn_printk(KERN_ERR, conn, "invalid R2T with zero data len\n"); - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); return ISCSI_ERR_DATALEN; } - if (r2t->data_length > session->max_burst) + if (data_length > session->max_burst) ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max " "burst %u. Attempting to execute request.\n", - r2t->data_length, session->max_burst); + data_length, session->max_burst); - r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) { + data_offset = be32_to_cpu(rhdr->data_offset); + if (data_offset + data_length > scsi_out(task->sc)->length) { iscsi_conn_printk(KERN_ERR, conn, "invalid R2T with data len %u at offset %u " - "and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_out(task->sc)->length); - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); + "and total length %d\n", data_length, + data_offset, scsi_out(task->sc)->length); return ISCSI_ERR_DATALEN; } + rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); + if (!rc) { + iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. " + "Target has sent more R2Ts than it " + "negotiated for or driver has leaked.\n"); + return ISCSI_ERR_PROTO; + } + + r2t->exp_statsn = rhdr->statsn; + r2t->data_length = data_length; + r2t->data_offset = data_offset; + r2t->ttt = rhdr->ttt; /* no flip */ r2t->datasn = 0; r2t->sent = 0; -- 1.7.1 -- 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
[PATCH 3/6] libiscsi: remove unneeded queue work when max_cmdsn is increased
From: Mike Christie iscsi_queuecommand will only take in commands that can fit in the current window. So, if a command is on the cmdqueue then it can fit in the current window. If a command is on the mgmtqueue, then we are setting the immediate bit so they will also fit in the window. As a result, we never need to to do a iscsi_conn_queue_work when the maxCmdSn is increased. What should happen is that a command will complete the window will be increased, then the scsi layer will send us more commands by running the scsi_device queues. Signed-off-by: Mike Christie --- drivers/scsi/libiscsi.c | 10 +- 1 files changed, 1 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 6afb6fc..9ca42a2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -110,16 +110,8 @@ static void __iscsi_update_cmdsn(struct iscsi_session *session, session->exp_cmdsn = exp_cmdsn; if (max_cmdsn != session->max_cmdsn && - !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) { + !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) session->max_cmdsn = max_cmdsn; - /* -* if the window closed with IO queued, then kick the -* xmit thread -*/ - if (!list_empty(&session->leadconn->cmdqueue) || - !list_empty(&session->leadconn->mgmtqueue)) - iscsi_conn_queue_work(session->leadconn); - } } void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) -- 1.7.1 -- 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
[PATCH 2/6] SCSI/libiscsi: Reduce locking contention in fast path (v2)
From: Shlomo Pongratz Replace the session lock with two locks, a forward lock and a backwards lock named frwd_lock and back_lock respectively. The forward lock protects resources that change while sending a request to the target, such as cmdsn, queued_cmdsn, and allocating task from the commands' pool with kfifo_out. The backward lock protects resources that change while processing a response or in error path, such as cmdsn_exp, cmdsn_max, and returning tasks to the commands' pool with kfifo_in. Under a steady state fast-path situation, that is when one or more processes/threads submit IO to an iscsi device and a single kernel upcall (e.g softirq) is dealing with processing of responses without errors, this patch eliminates the contention between the queuecommand()/request response/scsi_done() flows associated with iscsi sessions. Between the forward and the backward locks exists a strict locking hierarchy. The mutual exclusion zone protected by the forward lock can enclose the mutual exclusion zone protected by the backward lock but not vice versa. For example, in iscsi_conn_teardown or in iscsi_xmit_data when there is a failure and __iscsi_put_task is called, the backward lock is taken while the forward lock is still taken. On the other hand, if in the RX path a nop is to be sent, for example in iscsi_handle_reject or __iscsi_complete_pdu than the forward lock is released and the backward lock is taken for the duration of iscsi_send_nopout, later the backward lock is released and the forward lock is retaken. libiscsi_tcp uses two kernel fifos the r2t pool and the r2t queue. The insertion and deletion from these queues didn't corespond to the assumption taken by the new forward/backwards session locking paradigm. That is, in iscsi_tcp_clenup_task which belongs to the RX (backwards) path, r2t is taken out from r2t queue and inserted to the r2t pool. In iscsi_tcp_get_curr_r2t which belong to the TX (forward) path, r2t is also inserted to the r2t pool and another r2t is pulled from r2t queue. Only in iscsi_tcp_r2t_rsp which is called in the RX path but can requeue to the TX path, r2t is taken from the r2t pool and inserted to the r2t queue. In order to cope with this situation, two spin locks were added, pool2queue and queue2pool. The former protects extracting from the r2t pool and inserting to the r2t queue, and the later protects the extracing from the r2t queue and inserting to the r2t pool. Signed-off-by: Shlomo Pongratz Signed-off-by: Or Gerlitz [minor fix up to apply cleanly and compile fix] Signed-off-by: Mike Christie --- drivers/scsi/be2iscsi/be_main.c | 26 +++--- drivers/scsi/bnx2i/bnx2i_hwi.c | 46 drivers/scsi/bnx2i/bnx2i_iscsi.c |8 +- drivers/scsi/iscsi_tcp.c | 22 ++-- drivers/scsi/libiscsi.c | 214 + drivers/scsi/libiscsi_tcp.c | 28 +++-- drivers/scsi/qla4xxx/ql4_isr.c |4 +- include/scsi/libiscsi.h | 17 ++- include/scsi/libiscsi_tcp.h |2 + 9 files changed, 206 insertions(+), 161 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1f37505..8d82f2c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -232,20 +232,20 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - spin_lock_bh(&session->lock); + spin_lock_bh(&session->frwd_lock); if (!aborted_task || !aborted_task->sc) { /* we raced */ - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->frwd_lock); return SUCCESS; } aborted_io_task = aborted_task->dd_data; if (!aborted_io_task->scsi_cmnd) { /* raced or invalid command */ - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->frwd_lock); return SUCCESS; } - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->frwd_lock); /* Invalidate WRB Posted for this Task */ AMAP_SET_BITS(struct amap_iscsi_wrb, invld, aborted_io_task->pwrb_handle->pwrb, @@ -307,9 +307,9 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) /* invalidate iocbs */ cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - spin_lock_bh(&session->lock); + spin_lock_bh(&session->frwd_lock); if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) { - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->frwd_lock); return FAILED; } conn = session->leadconn; @@ -338,7 +338,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) num_invalidate++; inv_tbl++; } - sp
[PATCH 0/6]: iscsi changes for scsi-misc (v2)
This patchset has Mellanox's libiscsi locking changes, and various fixes. V2 - Fix for MaxCmdSn handling in patch 3/6 where the part of the function that also updates the MaxCmdSn also got cut by accident. -- 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
[PATCH 6/6] iscsi_tcp: check for valid session before accessing
From: Mike Christie Check that the session is setup before accessing its connection. This fixes a oops where userspace tries to get the ip address before the session is bound to a host. Signed-off-by: Mike Christie --- drivers/scsi/iscsi_tcp.c |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 12b3512..bfb6d07 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -759,6 +759,9 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, switch (param) { case ISCSI_HOST_PARAM_IPADDRESS: + if (!session) + return -ENOTCONN; + spin_lock_bh(&session->frwd_lock); conn = session->leadconn; if (!conn) { -- 1.7.1 -- 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
[PATCH 3/6] SCSI/libiscsi: Remove unneeded code
From: Shlomo Pongratz We never will have a closed window and something on one of those lists. Signed-off-by: Mike Christie Signed-off-by: Shlomo Pongratz --- drivers/scsi/libiscsi.c | 12 1 files changed, 0 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index e77c41f..cc19cc2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -108,18 +108,6 @@ static void __iscsi_update_cmdsn(struct iscsi_session *session, if (exp_cmdsn != session->exp_cmdsn && !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn)) session->exp_cmdsn = exp_cmdsn; - - if (max_cmdsn != session->max_cmdsn && - !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) { - session->max_cmdsn = max_cmdsn; - /* -* if the window closed with IO queued, then kick the -* xmit thread -*/ - if (!list_empty(&session->leadconn->cmdqueue) || - !list_empty(&session->leadconn->mgmtqueue)) - iscsi_conn_queue_work(session->leadconn); - } } void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) -- 1.7.1 -- 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
[PATCH 4/6] be2iscsi: fix lun test in device reset callout
From: Mike Christie We want to be checking the scsi_cmnd's lun against the possible tasks in the driver. Current check tests task against itself which was useless. Signed-off-by: Mike Christie --- drivers/scsi/be2iscsi/be_main.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1fb16b1..3ffe8ca 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -325,7 +325,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE) continue; - if (abrt_task->sc->device->lun != abrt_task->sc->device->lun) + if (sc->device->lun != abrt_task->sc->device->lun) continue; /* Invalidate WRB Posted for this Task */ -- 1.7.1 -- 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
[PATCH 5/6] iscsi_boot_sysfs: Fix a memory leak in iscsi_boot_destroy_kset()
From: Ethan Zhao Load and unload iscsi_ibft module will cause kernel memory leak, fix it in scsi/iscsi_boot_sysfs.c iscsi_boot_destroy_kset(). Signed-off-by: Ethan Zhao Signed-off-by: Mike Christie --- drivers/scsi/iscsi_boot_sysfs.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index 14c1c8f..680bf6f 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -490,5 +490,6 @@ void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) iscsi_boot_remove_kobj(boot_kobj); kset_unregister(boot_kset->kset); + kfree(boot_kset); } EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); -- 1.7.1 -- 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
[PATCH 6/6] iscsi_tcp: check for valid session before accessing
From: Mike Christie Check that the session is setup before accessing its connection. This fixes a oops where userspace tries to get the ip address before the session is bound to a host. Signed-off-by: Mike Christie --- drivers/scsi/iscsi_tcp.c |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 12b3512..bfb6d07 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -759,6 +759,9 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, switch (param) { case ISCSI_HOST_PARAM_IPADDRESS: + if (!session) + return -ENOTCONN; + spin_lock_bh(&session->frwd_lock); conn = session->leadconn; if (!conn) { -- 1.7.1 -- 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
[PATCH 2/6] SCSI/libiscsi: Reduce locking contention in fast path
From: Shlomo Pongratz Replace the session lock with two locks, a forward lock and a backwards lock named frwd_lock and back_lock respectively. The forward lock protects resources that change while sending a request to the target, such as cmdsn, queued_cmdsn, and allocating task from the commands' pool with kfifo_out. The backward lock protects resources that change while processing a response or in error path, such as cmdsn_exp, cmdsn_max, and returning tasks to the commands' pool with kfifo_in. Under a steady state fast-path situation, that is when one or more processes/threads submit IO to an iscsi device and a single kernel upcall (e.g softirq) is dealing with processing of responses without errors, this patch eliminates the contention between the queuecommand()/request response/scsi_done() flows associated with iscsi sessions. Between the forward and the backward locks exists a strict locking hierarchy. The mutual exclusion zone protected by the forward lock can enclose the mutual exclusion zone protected by the backward lock but not vice versa. For example, in iscsi_conn_teardown or in iscsi_xmit_data when there is a failure and __iscsi_put_task is called, the backward lock is taken while the forward lock is still taken. On the other hand, if in the RX path a nop is to be sent, for example in iscsi_handle_reject or __iscsi_complete_pdu than the forward lock is released and the backward lock is taken for the duration of iscsi_send_nopout, later the backward lock is released and the forward lock is retaken. libiscsi_tcp uses two kernel fifos the r2t pool and the r2t queue. The insertion and deletion from these queues didn't corespond to the assumption taken by the new forward/backwards session locking paradigm. That is, in iscsi_tcp_clenup_task which belongs to the RX (backwards) path, r2t is taken out from r2t queue and inserted to the r2t pool. In iscsi_tcp_get_curr_r2t which belong to the TX (forward) path, r2t is also inserted to the r2t pool and another r2t is pulled from r2t queue. Only in iscsi_tcp_r2t_rsp which is called in the RX path but can requeue to the TX path, r2t is taken from the r2t pool and inserted to the r2t queue. In order to cope with this situation, two spin locks were added, pool2queue and queue2pool. The former protects extracting from the r2t pool and inserting to the r2t queue, and the later protects the extracing from the r2t queue and inserting to the r2t pool. Signed-off-by: Shlomo Pongratz Signed-off-by: Or Gerlitz [minor fix up to apply cleanly] Signed-off-by: Mike Christie --- drivers/scsi/be2iscsi/be_main.c | 26 +++--- drivers/scsi/bnx2i/bnx2i_hwi.c | 46 +- drivers/scsi/bnx2i/bnx2i_iscsi.c |8 +- drivers/scsi/iscsi_tcp.c | 22 ++-- drivers/scsi/libiscsi.c | 192 ++ drivers/scsi/libiscsi_tcp.c | 28 -- drivers/scsi/qla4xxx/ql4_isr.c |4 +- include/scsi/libiscsi.h | 17 +++- include/scsi/libiscsi_tcp.h |2 + 9 files changed, 195 insertions(+), 150 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1f37505..1fb16b1 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -232,20 +232,20 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - spin_lock_bh(&session->lock); + spin_lock_bh(&session->frwd_lock); if (!aborted_task || !aborted_task->sc) { /* we raced */ - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->fwrd_lock); return SUCCESS; } aborted_io_task = aborted_task->dd_data; if (!aborted_io_task->scsi_cmnd) { /* raced or invalid command */ - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->fwrd_lock); return SUCCESS; } - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->fwrd_lock); /* Invalidate WRB Posted for this Task */ AMAP_SET_BITS(struct amap_iscsi_wrb, invld, aborted_io_task->pwrb_handle->pwrb, @@ -307,9 +307,9 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) /* invalidate iocbs */ cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - spin_lock_bh(&session->lock); + spin_lock_bh(&session->frwd_lock); if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) { - spin_unlock_bh(&session->lock); + spin_unlock_bh(&session->frwd_lock); return FAILED; } conn = session->leadconn; @@ -338,7 +338,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) num_invalidate++; inv_tbl++; } - spin_unlock_b
[PATCH 1/6] SCSI/libiscsi: Restructure iscsi_tcp r2t response logic
From: Shlomo Pongratz Restructure the iscsi_tcp_r2t_rsp routine in order to avoid allocating r2t from r2tpool.queue and returning it back in case the parameters rhdr->data_length and or rhdr->data_offset prohibit the requing. Since the values of these parameters are known prior to the allocation, we can pre-check and thus avoid futile allocations. Signed-off-by: Shlomo Pongratz Signed-off-by: Or Gerlitz Signed-off-by: Mike Christie --- drivers/scsi/libiscsi_tcp.c | 43 ++- 1 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 1d58d53..7f59073 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -529,6 +529,8 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; struct iscsi_r2t_info *r2t; int r2tsn = be32_to_cpu(rhdr->r2tsn); + u32 data_length; + u32 data_offset; int rc; if (tcp_conn->in.datalen) { @@ -554,40 +556,39 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) return 0; } - rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); - if (!rc) { - iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. " - "Target has sent more R2Ts than it " - "negotiated for or driver has leaked.\n"); - return ISCSI_ERR_PROTO; - } - - r2t->exp_statsn = rhdr->statsn; - r2t->data_length = be32_to_cpu(rhdr->data_length); - if (r2t->data_length == 0) { + data_length = be32_to_cpu(rhdr->data_length); + if (data_length == 0) { iscsi_conn_printk(KERN_ERR, conn, "invalid R2T with zero data len\n"); - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); return ISCSI_ERR_DATALEN; } - if (r2t->data_length > session->max_burst) + if (data_length > session->max_burst) ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max " "burst %u. Attempting to execute request.\n", - r2t->data_length, session->max_burst); + data_length, session->max_burst); - r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) { + data_offset = be32_to_cpu(rhdr->data_offset); + if (data_offset + data_length > scsi_out(task->sc)->length) { iscsi_conn_printk(KERN_ERR, conn, "invalid R2T with data len %u at offset %u " - "and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_out(task->sc)->length); - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); + "and total length %d\n", data_length, + data_offset, scsi_out(task->sc)->length); return ISCSI_ERR_DATALEN; } + rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); + if (!rc) { + iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. " + "Target has sent more R2Ts than it " + "negotiated for or driver has leaked.\n"); + return ISCSI_ERR_PROTO; + } + + r2t->exp_statsn = rhdr->statsn; + r2t->data_length = data_length; + r2t->data_offset = data_offset; + r2t->ttt = rhdr->ttt; /* no flip */ r2t->datasn = 0; r2t->sent = 0; -- 1.7.1 -- 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
[PATCH 0/6] iscsi changes for scsi-misc
The following patches are some features and fixes for scsi-misc. James, if you were going to merge the libiscsi locking changes here http://www.spinics.net/lists/linux-scsi/msg69903.html do not bother. The qlogic patches that were just merged had a conflict. The patches in the following emails should apply cleanly to misc. -- 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
[PATCH] block: free bios when failing blk_execute_rq_nowait calls
From: Mike Christie If the queue is dying then we only call the rq->end_io callout. This leaves bios setup on the request, because the caller assumes when the blk_execute_rq_nowait/blk_execute_rq call has completed that the rq->bios have been cleaned up. This patch has blk_execute_rq_nowait use __blk_end_request_all to free bios and also call rq->end_io. Signed-off-by: Mike Christie --- block/blk-exec.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/block/blk-exec.c b/block/blk-exec.c index e706213..ae4f27d 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -68,9 +68,9 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, spin_lock_irq(q->queue_lock); if (unlikely(blk_queue_dying(q))) { + rq->cmd_flags |= REQ_QUIET; rq->errors = -ENXIO; - if (rq->end_io) - rq->end_io(rq, rq->errors); + __blk_end_request_all(rq, rq->errors); spin_unlock_irq(q->queue_lock); return; } -- 1.7.1 -- 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
[PATCH 1/2] libiscsi: avoid unnecessary multiple NULL assignments
From: Masatake YAMATO In iscsi_free_task, NULL is assigned to task->sc twice: before and after kfifo_in invocatoin. Allocating and freeing iscsi_task are guarded with session->lock, so multiple NULL assignments cause no trouble. But people reading the source code may be confused. The second NULL assignment comes from commit: 3e5c28ad0391389959ccae81c938c7533efb3490 It seems that the line after kfifo_in invocation was introduced accidentally. Signed-off-by: Masatake YAMATO Reviewed-by: Mike Christie Signed-off-by: Mike Christie --- drivers/scsi/libiscsi.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d5e5c44..5de9469 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -507,7 +507,6 @@ static void iscsi_free_task(struct iscsi_task *task) kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*)); if (sc) { - task->sc = NULL; /* SCSI eh reuses commands to verify us */ sc->SCp.ptr = NULL; /* -- 1.7.1 -- 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
[PATCH 2/2] iscsi_tcp: support PF_MEMALLOC/__GFP_MEMALLOC
From: Mike Christie This patch has software iscsi use PF_MEMALLOC/__GFP_MEMALLOC to be able to better support swap over iscsi disks similar to what was added for nbd. Signed-off-by: Mike Christie --- drivers/scsi/iscsi_tcp.c | 18 +- 1 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 1b91ca0..9e2588a 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -370,17 +370,24 @@ static inline int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn) static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task) { struct iscsi_conn *conn = task->conn; - int rc; + unsigned long pflags = current->flags; + int rc = 0; + + current->flags |= PF_MEMALLOC; while (iscsi_sw_tcp_xmit_qlen(conn)) { rc = iscsi_sw_tcp_xmit(conn); - if (rc == 0) - return -EAGAIN; + if (rc == 0) { + rc = -EAGAIN; + break; + } if (rc < 0) - return rc; + break; + rc = 0; } - return 0; + tsk_restore_flags(current, pflags, PF_MEMALLOC); + return rc; } /* @@ -665,6 +672,7 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session, sk->sk_reuse = SK_CAN_REUSE; sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ sk->sk_allocation = GFP_ATOMIC; + sk_set_memalloc(sk); iscsi_sw_tcp_conn_set_callbacks(conn); tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage; -- 1.7.1 -- 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
[PATCH 0/2] iscsi changes for scsi misc
The following 2 patches are for the misc branch in the scsi tree. They cleanup duplicated code from a previous patch and add better support for swap over software iscsi by using the PF_MEMALLOC/__GFP_MEMALLOC flags like what was recently added for nbd. -- 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
[PATCH 1/1] scsi_dh_alua: fix stpg sense handling
From: Mike Christie For the stpg_endio path we are not evaluating the sense. The bug is that 1. The error value is set to -EIO when there is sense, so we hit the first error check and always return SCSI_DH_IO. 2. h->senselen is set to zero in submit_stpg. It is not later set to req->sense_len like in the synchrounous exection paths, so we must check the req->sense_len field. Signed-off-by: Mike Christie --- drivers/scsi/device_handler/scsi_dh_alua.c | 10 ++ 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 6f4d8e6..6648ffb 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -232,13 +232,13 @@ static void stpg_endio(struct request *req, int error) struct scsi_sense_hdr sense_hdr; unsigned err = SCSI_DH_OK; - if (error || host_byte(req->errors) != DID_OK || - msg_byte(req->errors) != COMMAND_COMPLETE) { + if (host_byte(req->errors) != DID_OK || + msg_byte(req->errors) != COMMAND_COMPLETE) { err = SCSI_DH_IO; goto done; } - if (h->senselen > 0) { + if (req->sense_len > 0) { err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!err) { @@ -255,7 +255,9 @@ static void stpg_endio(struct request *req, int error) ALUA_DH_NAME, sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); err = SCSI_DH_IO; - } + } else if (error) + err = SCSI_DH_IO; + if (err == SCSI_DH_OK) { h->state = TPGS_STATE_OPTIMIZED; sdev_printk(KERN_INFO, h->sdev, -- 1.7.1 -- 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
[PATCH 1/1] iscsi regression: check for zero max session cmds
From: Mike Christie <[EMAIL PROTECTED]> The old tools did not set max session cmds. This is a regression. I removed the check when merging the power of 2 patch. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |4 ++-- drivers/scsi/scsi_transport_iscsi.c |2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 59f8445..bdd7de7 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1708,8 +1708,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, qdepth = ISCSI_DEF_CMD_PER_LUN; } - if (!is_power_of_2(cmds_max) || - cmds_max >= ISCSI_MGMT_ITT_OFFSET) { + if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET || + cmds_max < 2) { if (cmds_max != 0) printk(KERN_ERR "iscsi: invalid can_queue of %d. " "can_queue must be a power of 2 and between " diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9981682..dfb026b 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -33,7 +33,7 @@ #define ISCSI_SESSION_ATTRS 19 #define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-868" +#define ISCSI_TRANSPORT_VERSION "2.0-869" struct iscsi_internal { int daemon_pid; -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] scsi-ml: Add helper code so transport classes can control queueing
From: Mike Christie <[EMAIL PROTECTED]> SCSI-ml manages the queueing limits for the device and host, but does not do so at the target level. Currently this is not needed and is probably more for the transport code to handle. However, for bnx2i we will need to be able to limit queueing at this level. bnx2i will hook into libiscsi, but will allocate a scsi host per netdevice/hba, so unlike pure software iscsi/iser which is allocating a host per session, it cannot set the scsi_host->can_queue and return SCSI_MLQUEUE_HOST_BUSY to reflect queueing limits on the transport. This patch adds some basic helper code for scsi-ml, that the transport classes can utilize. The patch adds code similar to the exisiting SCSI_ML_*BUSY handlers. You can now return SCSI_MLQUEUE_TARGET_BUSY when we hit a transport level queueing issue like the hw cannot allocate some resource at the iscsi session/connection level or the target has temporarily closed or shrunk the queueing window. The iscsi class/driver can also set a scsi_target->can_queue value which reflects the max commands the driver/class can support. For iscsi this reflects the number of commands we can support for each session due to session/connection hw limits, driver limits, and to also reflect the session/targets's queueing window. This patch was made over the last patchset I sent. It is not for mergeing into 2.6.25 or scsi-misc yet. I just want to put it out here, and make sure it is ok and get feedback on what else I might need to do for this patch before broadcom and I push the bnx2i driver. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi.c| 11 +-- drivers/scsi/scsi_lib.c| 70 +-- drivers/scsi/scsi_scan.c |1 + include/scsi/scsi.h|1 + include/scsi/scsi_device.h | 10 ++ 5 files changed, 80 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index b35d194..339760a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -628,9 +628,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) if (rtn) { if (scsi_delete_timer(cmd)) { atomic_inc(&cmd->device->iodone_cnt); - scsi_queue_insert(cmd, - (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ? - rtn : SCSI_MLQUEUE_HOST_BUSY); + + if (rtn != SCSI_MLQUEUE_DEVICE_BUSY && + rtn != SCSI_MLQUEUE_TARGET_BUSY) + rtn = SCSI_MLQUEUE_HOST_BUSY; + + scsi_queue_insert(cmd, rtn); } SCSI_LOG_MLQUEUE(3, printk("queuecommand : request rejected\n")); @@ -729,6 +732,7 @@ static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) void scsi_finish_command(struct scsi_cmnd *cmd) { struct scsi_device *sdev = cmd->device; + struct scsi_target *starget = scsi_target(sdev); struct Scsi_Host *shost = sdev->host; struct scsi_driver *drv; unsigned int good_bytes; @@ -744,6 +748,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) * XXX(hch): What about locking? */ shost->host_blocked = 0; + starget->target_blocked = 0; sdev->device_blocked = 0; /* diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b12fb31..9c76d10 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -114,6 +114,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; + struct scsi_target *starget = scsi_target(device); struct request_queue *q = device->request_queue; unsigned long flags; @@ -133,10 +134,17 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) * if a command is requeued with no other commands outstanding * either for the device or for the host. */ - if (reason == SCSI_MLQUEUE_HOST_BUSY) - host->host_blocked = host->max_host_blocked; - else if (reason == SCSI_MLQUEUE_DEVICE_BUSY) - device->device_blocked = device->max_device_blocked; + switch (reason) { + case SCSI_MLQUEUE_HOST_BUSY: + host->host_blocked = host->max_host_blocked; + break; + case SCSI_MLQUEUE_DEVICE_BUSY: + device->device_blocked = device->max_device_blocked; + break; + case SCSI_MLQUEUE_TARGET_BUSY: + starget->target_blocked = starget->max_target_blocked; + break; + } /* * Decrement the counters, since these commands are no longer @@ -452,10 +460,12 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd) void scsi_device_unbusy(struct scsi_device *sdev) { struct Scsi_Host *shost = sdev->ho
[PATCH 2/2] iscsi: user per target can_queue
From: Mike Christie <[EMAIL PROTECTED]> This hooks iscsi_tcp and libiscsi into the target->can_queue code and it has libiscsi use SCSI_MLQUEUE_TARGET_BUSY. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/infiniband/ulp/iser/iscsi_iser.c |1 + drivers/scsi/iscsi_tcp.c |1 + drivers/scsi/libiscsi.c | 19 +-- include/scsi/libiscsi.h |1 + 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index be1b9fb..c818707 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -552,6 +552,7 @@ static struct scsi_host_template iscsi_iser_sht = { .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, .max_sectors= 1024, .cmd_per_lun= ISCSI_MAX_CMD_PER_LUN, + .slave_alloc= iscsi_slave_alloc, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler= iscsi_eh_device_reset, .eh_host_reset_handler = iscsi_eh_host_reset, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8a17867..c63e0e8 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1936,6 +1936,7 @@ static struct scsi_host_template iscsi_sht = { .eh_device_reset_handler= iscsi_eh_device_reset, .eh_host_reset_handler = iscsi_eh_host_reset, .use_clustering = DISABLE_CLUSTERING, + .slave_alloc= iscsi_slave_alloc, .slave_configure= iscsi_tcp_slave_configure, .proc_name = "iscsi_tcp", .this_id= -1, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 59f8445..6d6770c 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1097,7 +1097,7 @@ reject: spin_unlock(&session->lock); debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); spin_lock(host->host_lock); - return SCSI_MLQUEUE_HOST_BUSY; + return SCSI_MLQUEUE_TARGET_BUSY; fault: spin_unlock(&session->lock); @@ -1118,6 +1118,21 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) } EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); +int iscsi_slave_alloc(struct scsi_device *sdev) +{ + struct scsi_target *starget = scsi_target(sdev); + struct iscsi_cls_session *cls_session = starget_to_session(starget); + struct iscsi_session *session; + + if (!cls_session || iscsi_session_chkready(cls_session)) + return -ENXIO; + + session = class_to_transport_session(cls_session); + starget->can_queue = session->cmds_max; + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_slave_alloc); + void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) { struct iscsi_session *session = class_to_transport_session(cls_session); @@ -1724,7 +1739,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, return NULL; /* the iscsi layer takes one task for reserve */ - shost->can_queue = cmds_max - 1; + shost->can_queue = cmds_max; shost->cmd_per_lun = qdepth; shost->max_id = 1; shost->max_channel = 0; diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 7b90b63..3c2bdc4 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -308,6 +308,7 @@ struct iscsi_session { /* * scsi host template */ +extern int iscsi_slave_alloc(struct scsi_device *sdev); extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth); extern int iscsi_eh_abort(struct scsi_cmnd *sc); extern int iscsi_eh_host_reset(struct scsi_cmnd *sc); -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Add target queueing limit helpers to scsi-ml
These two patches are for RFC, but could go into scsi-misc for 2.6.26 if they are ok off the bat. They add the ability to limit queueing at the target level. This will be needed for bnx2i, but also may be useful to limit transport level commands when using bsg. - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/12] bump iscsi version
From: Mike Christie <[EMAIL PROTECTED]> Set iscsi version to 2.0-868 Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi_transport_iscsi.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 8e73ff0..fac7534 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -33,7 +33,7 @@ #define ISCSI_SESSION_ATTRS 19 #define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-867" +#define ISCSI_TRANSPORT_VERSION "2.0-868" struct iscsi_internal { int daemon_pid; -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/12] iscsi: fix up iscsi printk prefix
From: Mike Christie <[EMAIL PROTECTED]> Some iscsi class messages have the dev_printk prefix and some libiscsi and iscsi_tcp messages have "iscsi" or the module name as a prefix which is normally pretty useless when trying to figure out which session or connection the message is attached to. This patch adds iscsi lib and class dev_printks so all messages have a common prefix that can be used to figure out which object printed it. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c| 57 ++ drivers/scsi/libiscsi.c | 76 --- drivers/scsi/scsi_transport_iscsi.c | 56 ++ include/scsi/libiscsi.h |7 +++ include/scsi/scsi_transport_iscsi.h |6 +++ 5 files changed, 116 insertions(+), 86 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b6f99df..8a17867 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -629,8 +629,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) int rc; if (tcp_conn->in.datalen) { - printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n", - tcp_conn->in.datalen); + iscsi_conn_printk(KERN_ERR, conn, + "invalid R2t with datalen %d\n", + tcp_conn->in.datalen); return ISCSI_ERR_DATALEN; } @@ -644,8 +645,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { - printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " - "recovery...\n", ctask->itt); + iscsi_conn_printk(KERN_INFO, conn, + "dropping R2T itt %d in recovery.\n", + ctask->itt); return 0; } @@ -655,7 +657,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->exp_statsn = rhdr->statsn; r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { - printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); + iscsi_conn_printk(KERN_ERR, conn, + "invalid R2T with zero data len\n"); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -668,9 +671,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " - "offset %u and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_bufflen(ctask->sc)); + iscsi_conn_printk(KERN_ERR, conn, + "invalid R2T with data len %u at offset %u " + "and total length %d\n", r2t->data_length, + r2t->data_offset, scsi_bufflen(ctask->sc)); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -736,8 +740,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); if (tcp_conn->in.datalen > conn->max_recv_dlength) { - printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n", - tcp_conn->in.datalen, conn->max_recv_dlength); + iscsi_conn_printk(KERN_ERR, conn, + "iscsi_tcp: datalen %d > %d\n", + tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } @@ -819,10 +824,12 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) * For now we fail until we find a vendor that needs it */ if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { - printk(KERN_ERR "iscsi_tcp: received buffer of len %u " - "but conn buffer is only %u (opcode %0x)\n", - tcp_conn->in.datalen, - ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); + iscsi_conn_printk(KERN_ERR, conn, + "iscsi_tcp: received buffer of " + "len %u but conn buffer is only %u " + "(opcode %0x)\n", +
[PATCH 11/12] libiscsi: fix session age rollover and remove cid encoding
From: Mike Christie <[EMAIL PROTECTED]> The session age mask is only 4 bits, but session->age is 32. When it gets larger then 15 and we try to or the bits some bits get dropped and the check for session age in iscsi_verify_itt is useless. The ISCSI_CID_MASK related bits are also useless since cid is always one. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c| 14 -- include/scsi/iscsi_proto.h |4 ++-- include/scsi/libiscsi.h|2 -- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c76bd5c..cfffabd 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -160,7 +160,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = build_itt(ctask->itt, conn->id, session->age); + hdr->itt = build_itt(ctask->itt, session->age); hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; @@ -706,14 +706,6 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, return ISCSI_ERR_BAD_ITT; } - if (((__force u32)hdr->itt & ISCSI_CID_MASK) != - (conn->id << ISCSI_CID_SHIFT)) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi: received itt %x, expected " - "CID (%x)\n", - (__force u32)hdr->itt, conn->id); - return ISCSI_ERR_BAD_ITT; - } itt = get_itt(hdr->itt); } else itt = ~0U; @@ -777,7 +769,7 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, */ nop->cmdsn = cpu_to_be32(session->cmdsn); if (hdr->itt != RESERVED_ITT) { - hdr->itt = build_itt(mtask->itt, conn->id, session->age); + hdr->itt = build_itt(mtask->itt, session->age); /* * TODO: We always use immediate, so we never hit this. * If we start to send tmfs or nops as non-immediate then @@ -2037,6 +2029,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage = 0; conn->tmf_state = TMF_INITIAL; session->age++; + if (session->age == 16) + session->age = 0; break; case STOP_CONN_TERM: conn->stop_stage = 0; diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index 318a909..5ffec8a 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h @@ -45,8 +45,8 @@ /* initiator tags; opaque for target */ typedef uint32_t __bitwise__ itt_t; /* below makes sense only for initiator that created this tag */ -#define build_itt(itt, id, age) ((__force itt_t)\ - ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT))) +#define build_itt(itt, age) ((__force itt_t)\ + ((itt) | ((age) << ISCSI_AGE_SHIFT))) #define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK) #define RESERVED_ITT ((__force itt_t)0x) diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 5daa83c..9b955a9 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -70,8 +70,6 @@ enum { #define ISCSI_SUSPEND_BIT 1 #define ISCSI_ITT_MASK (0xfff) -#define ISCSI_CID_SHIFT12 -#define ISCSI_CID_MASK (0x << ISCSI_CID_SHIFT) #define ISCSI_AGE_SHIFT28 #define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/12] iscsi class: fix iscsi conn attr counter
From: Mike Christie <[EMAIL PROTECTED]> There are 13 iscsi conn attrs, but since the IF/OF markers were not being used we did not notice that we forgot to increment the ISCSI_CONN_ATTRS counter. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi_transport_iscsi.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index af17997..35834bf 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -31,7 +31,7 @@ #include #define ISCSI_SESSION_ATTRS 19 -#define ISCSI_CONN_ATTRS 11 +#define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 #define ISCSI_TRANSPORT_VERSION "2.0-867" -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/12] libiscsi: fix setting of nop timer
From: Mike Christie <[EMAIL PROTECTED]> If we rollover then we could get a next_timeout of zero, so we need to set the new timer to that value. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |9 +++-- 1 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8c41ddb..7e781fd 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1385,14 +1385,11 @@ static void iscsi_check_transport_timeouts(unsigned long data) iscsi_send_nopout(conn, NULL); } next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); - } else { + } else next_timeout = last_recv + timeout; - } - if (next_timeout) { - debug_scsi("Setting next tmo %lu\n", next_timeout); - mod_timer(&conn->transport_timer, next_timeout); - } + debug_scsi("Setting next tmo %lu\n", next_timeout); + mod_timer(&conn->transport_timer, next_timeout); done: spin_unlock(&session->lock); } -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 07/12] qla4xxx: add qla4xxx async scan support
From: Mike Christie <[EMAIL PROTECTED]> qla4xxx has the old school startup/probe where it finds presetup sessions in its flash and then attempts to log into them before returning from the probe. This however, makes it very simple to add a iscsi class scan finished helper which the driver can use. In future patches Dave or I will rip apart the driver to make it more like qla2xxx, but for now this is a very simple two line patch which fixes the problem of trying to figure out when the initial sessions are done being scanned. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/qla4xxx/ql4_os.c |4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index d4dd149..c3c59d7 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -89,6 +89,8 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_alloc= qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, + .scan_finished = iscsi_scan_finished, + .this_id= -1, .cmd_per_lun= 3, .use_clustering = ENABLE_CLUSTERING, @@ -1306,7 +1308,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - + scsi_scan_host(host); return 0; remove_host: -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/12] iscsi class: add session scanning
From: Mike Christie <[EMAIL PROTECTED]> This just adds iscsi session scanning which works like fc rport scanning. The future patches will hook the drivers into Mathew Wilcox's async scanning infrastructure, so userspace does not have to special case iscsi and so userspace does not have to make a extra special case for hardware iscsi root scanning. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi_transport_iscsi.c | 37 -- include/scsi/scsi_transport_iscsi.h |7 +++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index f876b0a..af88955 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -128,11 +128,11 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); - snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", + snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", shost->host_no); - ihost->unbind_workq = create_singlethread_workqueue( - ihost->unbind_workq_name); - if (!ihost->unbind_workq) + ihost->scan_workq = create_singlethread_workqueue( + ihost->scan_workq_name); + if (!ihost->scan_workq) return -ENOMEM; return 0; } @@ -143,7 +143,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, struct Scsi_Host *shost = dev_to_shost(dev); struct iscsi_host *ihost = shost->shost_data; - destroy_workqueue(ihost->unbind_workq); + destroy_workqueue(ihost->scan_workq); return 0; } @@ -302,6 +302,23 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, return 0; } +static void iscsi_scan_session(struct work_struct *work) +{ + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, scan_work); + unsigned long flags; + + spin_lock_irqsave(&session->lock, flags); + if (session->state != ISCSI_SESSION_LOGGED_IN) { + spin_unlock_irqrestore(&session->lock, flags); + return; + } + spin_unlock_irqrestore(&session->lock, flags); + + scsi_scan_target(&session->dev, 0, session->target_id, +SCAN_WILD_CARD, 1); +} + static void session_recovery_timedout(struct work_struct *work) { struct iscsi_cls_session *session = @@ -340,6 +357,8 @@ void __iscsi_unblock_session(struct iscsi_cls_session *session) void iscsi_unblock_session(struct iscsi_cls_session *session) { + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; unsigned long flags; spin_lock_irqsave(&session->lock, flags); @@ -347,6 +366,7 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) spin_unlock_irqrestore(&session->lock, flags); __iscsi_unblock_session(session); + queue_work(ihost->scan_workq, &session->scan_work); } EXPORT_SYMBOL_GPL(iscsi_unblock_session); @@ -390,7 +410,7 @@ static int iscsi_unbind_session(struct iscsi_cls_session *session) struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; - return queue_work(ihost->unbind_workq, &session->unbind_work); + return queue_work(ihost->scan_workq, &session->unbind_work); } struct iscsi_cls_session * @@ -411,6 +431,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); + INIT_WORK(&session->scan_work, iscsi_scan_session); spin_lock_init(&session->lock); /* this is released in the dev's release function */ @@ -530,13 +551,15 @@ void iscsi_remove_session(struct iscsi_cls_session *session) spin_unlock_irqrestore(&session->lock, flags); __iscsi_unblock_session(session); iscsi_unbind_session(session); + + /* flush running scans */ + flush_workqueue(ihost->scan_workq); /* * If the session dropped while removing devices then we need to make * sure it is not blocked */ if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); - flush_workqueue(ihost->unbind_workq); /* hw iscsi may not have removed all connections from session */ err = device_for_each_child(&session->dev, NULL, diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 0e869d9..1f0ec46 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/sc
[PATCH 06/12] iscsi class: add async scan helper
From: Mike Christie <[EMAIL PROTECTED]> In qla4xxx's probe it will call the iscsi session setup functions for session that got setup on the initial start. This then makes it easy for the iscsi class to export a helper which indicates when those scans are done. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi_transport_iscsi.c | 38 -- include/scsi/scsi_transport_iscsi.h |3 +- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index af88955..af17997 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -127,6 +127,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); + atomic_set(&ihost->nr_scans, 0); snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", shost->host_no); @@ -284,6 +285,25 @@ static int iscsi_is_session_dev(const struct device *dev) return dev->release == iscsi_session_release; } +/** + * iscsi_scan_finished - helper to report when running scans are done + * @shost: scsi host + * @time: scan run time + * + * This function can be used by drives like qla4xxx to report to the scsi + * layer when the scans it kicked off at module load time are done. + */ +int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + struct iscsi_host *ihost = shost->shost_data; + /* +* qla4xxx will have kicked off some session unblocks before calling +* scsi_scan_host, so just wait for them to complete. +*/ + return !atomic_read(&ihost->nr_scans); +} +EXPORT_SYMBOL_GPL(iscsi_scan_finished); + static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun) { @@ -306,17 +326,21 @@ static void iscsi_scan_session(struct work_struct *work) { struct iscsi_cls_session *session = container_of(work, struct iscsi_cls_session, scan_work); + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; unsigned long flags; spin_lock_irqsave(&session->lock, flags); if (session->state != ISCSI_SESSION_LOGGED_IN) { spin_unlock_irqrestore(&session->lock, flags); - return; + goto done; } spin_unlock_irqrestore(&session->lock, flags); scsi_scan_target(&session->dev, 0, session->target_id, SCAN_WILD_CARD, 1); +done: + atomic_dec(&ihost->nr_scans); } static void session_recovery_timedout(struct work_struct *work) @@ -366,7 +390,15 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) spin_unlock_irqrestore(&session->lock, flags); __iscsi_unblock_session(session); - queue_work(ihost->scan_workq, &session->scan_work); + /* +* Only do kernel scanning if the driver is properly hooked into +* the async scanning code (drivers like iscsi_tcp do login and +* scanning from userspace). +*/ + if (shost->hostt->scan_finished) { + if (queue_work(ihost->scan_workq, &session->scan_work)) + atomic_inc(&ihost->nr_scans); + } } EXPORT_SYMBOL_GPL(iscsi_unblock_session); @@ -550,7 +582,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) session->state = ISCSI_SESSION_FREE; spin_unlock_irqrestore(&session->lock, flags); __iscsi_unblock_session(session); - iscsi_unbind_session(session); + __iscsi_unbind_session(&session->unbind_work); /* flush running scans */ flush_workqueue(ihost->scan_workq); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 1f0ec46..83693ba 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -203,6 +203,7 @@ struct iscsi_cls_session { struct iscsi_host { struct list_head sessions; + atomic_t nr_scans; struct mutex mutex; struct workqueue_struct *scan_workq; char scan_workq_name[KOBJ_NAME_LEN]; @@ -229,6 +230,6 @@ extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); extern void iscsi_unblock_session(struct iscsi_cls_session *session); extern void iscsi_block_session(struct iscsi_cls_session *session); - +extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); #endif -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 05/12] qla4xxx: fix recovery timer and session unblock race
From: Mike Christie <[EMAIL PROTECTED]> If qla4xxx is resetting up a session and the recovery timer fires we do not want to just set it to dead, because the dpc thread could have just set it to online and is in the middle of resetting it up. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/qla4xxx/ql4_os.c | 19 +++ 1 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 437d169..d4dd149 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -124,16 +124,19 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) struct ddb_entry *ddb_entry = session->dd_data; struct scsi_qla_host *ha = ddb_entry->ha; - DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) " - "secs exhausted, marking device DEAD.\n", ha->host_no, - __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - atomic_set(&ddb_entry->state, DDB_STATE_DEAD); + DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count " + "of (%d) secs exhausted, marking device DEAD.\n", + ha->host_no, __func__, ddb_entry->fw_ddb_index, + ha->port_down_retry_count)); - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " - "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); - queue_work(ha->dpc_thread, &ha->dpc_work); + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc " + "flags = 0x%lx\n", + ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); + } } static int qla4xxx_host_get_param(struct Scsi_Host *shost, -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/12] qla4xxx: have qla4xxx use iscsi class session state check ready
From: Mike Christie <[EMAIL PROTECTED]> This has qla4xxx use the iscsi class's check ready function in the queue command function, so all iscsi drivers return the same error value for common problems. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/qla4xxx/ql4_os.c | 12 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index a87fb9f..437d169 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -398,9 +398,21 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, { struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; + struct iscsi_cls_session *sess = ddb_entry->sess; struct srb *srb; int rval; + if (!sess) { + cmd->result = DID_IMM_RETRY << 16; + goto qc_fail_command; + } + + rval = iscsi_session_chkready(sess); + if (rval) { + cmd->result = rval; + goto qc_fail_command; + } + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { cmd->result = DID_NO_CONNECT << 16; -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/12] qla4xxx: have qla4xxx directly call iscsi recovery functions
From: Mike Christie <[EMAIL PROTECTED]> Qla4xxx can just call the iscsi recovery functions directly. There is no need for userspace to do this for qla4xxx, because we do not use the mutex to iterate over devices anymore and iscsi_block /unblock_session can be called from interrupt context or the dpc thread. And having userspace do this just creates uneeded headaches for qla4xxx root situations where the session may experience problems. For example during the kernel shutdown the scsi layer wants to send sync caches, but at this time userspace is not up (iscsid is not running), so we cannot recover from the problem. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/qla4xxx/ql4_init.c |1 + drivers/scsi/qla4xxx/ql4_os.c | 40 +++--- 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index cbe0a17..03e66cb 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1306,6 +1306,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); + iscsi_unblock_session(ddb_entry->sess); iscsi_session_event(ddb_entry->sess, ISCSI_KEVENT_CREATE_SESSION); /* diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2e2b9fe..a87fb9f 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -63,8 +63,6 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf); static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf); -static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag); -static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); /* @@ -116,8 +114,6 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, .get_host_param = qla4xxx_host_get_param, - .start_conn = qla4xxx_conn_start, - .stop_conn = qla4xxx_conn_stop, .session_recovery_timedout = qla4xxx_recovery_timedout, }; @@ -140,38 +136,6 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) queue_work(ha->dpc_thread, &ha->dpc_work); } -static int qla4xxx_conn_start(struct iscsi_cls_conn *conn) -{ - struct iscsi_cls_session *session; - struct ddb_entry *ddb_entry; - - session = iscsi_dev_to_session(conn->dev.parent); - ddb_entry = session->dd_data; - - DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); - iscsi_unblock_session(session); - return 0; -} - -static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) -{ - struct iscsi_cls_session *session; - struct ddb_entry *ddb_entry; - - session = iscsi_dev_to_session(conn->dev.parent); - ddb_entry = session->dd_data; - - DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); - if (flag == STOP_CONN_RECOVER) - iscsi_block_session(session); - else - printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); -} - static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { @@ -308,6 +272,9 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) DEBUG2(printk(KERN_ERR "Could not add connection.\n")); return -ENOMEM; } + + /* finally ready to go */ + iscsi_unblock_session(ddb_entry->sess); return 0; } @@ -364,6 +331,7 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index)); + iscsi_block_session(ddb_entry->sess); iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); } -- 1.5.2.1 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/12] iscsi class, libiscsi: add iscsi sysfs session state file
From: Mike Christie <[EMAIL PROTECTED]> This adds a iscsi session state file which exports the session state for both software and hardware iscsi. It also hooks libiscsi in. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c | 41 +- drivers/scsi/scsi_transport_iscsi.c | 107 ++- include/scsi/libiscsi.h | 19 ++ include/scsi/scsi_transport_iscsi.h | 27 - 4 files changed, 161 insertions(+), 33 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 553168a..8c41ddb 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -997,6 +997,7 @@ enum { FAILURE_SESSION_IN_RECOVERY, FAILURE_SESSION_RECOVERY_TIMEOUT, FAILURE_SESSION_LOGGING_OUT, + FAILURE_SESSION_NOT_READY, }; int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) @@ -1017,6 +1018,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); + reason = iscsi_session_chkready(session_to_cls(session)); + if (reason) { + sc->result = reason; + goto fault; + } + /* * ISCSI_STATE_FAILED is a temp. state. The recovery * code will decide what is best to do with command queued @@ -1033,18 +1040,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) switch (session->state) { case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; - goto reject; + sc->result = DID_IMM_RETRY << 16; + break; case ISCSI_STATE_LOGGING_OUT: reason = FAILURE_SESSION_LOGGING_OUT; - goto reject; + sc->result = DID_IMM_RETRY << 16; + break; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; + sc->result = DID_NO_CONNECT << 16; break; case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; + sc->result = DID_NO_CONNECT << 16; break; default: reason = FAILURE_SESSION_FREED; + sc->result = DID_NO_CONNECT << 16; } goto fault; } @@ -1052,6 +1064,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) conn = session->leadconn; if (!conn) { reason = FAILURE_SESSION_FREED; + sc->result = DID_NO_CONNECT << 16; goto fault; } @@ -1091,9 +1104,7 @@ reject: fault: spin_unlock(&session->lock); - printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", - sc->cmnd[0], reason); - sc->result = (DID_NO_CONNECT << 16); + debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); spin_lock(host->host_lock); @@ -1239,7 +1250,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, * Fail commands. session lock held and recv side suspended and xmit * thread flushed */ -static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) +static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, + int error) { struct iscsi_cmd_task *ctask, *tmp; @@ -1251,7 +1263,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, DID_BUS_BUSY << 16); + fail_command(conn, ctask, error << 16); } } @@ -1259,7 +1271,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing requeued sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, DID_BUS_BUSY << 16); + fail_command(conn, ctask, error << 16); } } @@ -1573,7 +1585,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) /* need to grab the recv lock then session lock */ write_lock_bh(conn->recv_lock); spin_lock(&session->lock); - fail_all_commands(conn, sc->device->lun); + fail_all_commands(conn, sc->device->lun, DID_ERROR); conn
iscsi update
The following patches were made over scsi-misc. The bugs fixed are: - Have qla4xxx hook into block/unblock code, and use new session state to fail/requeue IO during transport problems. - Hook qla4xxx into async scanning code. Qla4xxx looks more like a normal old scsi card than a iscsi card. There is very little iscsi stuff going on in the driver, so it is much easier to just have this type of iscsi card work like other FC and SPI cards. Currently distros are doing crazy things to special case qla4xxx, so you can boot from it. - Fix libiscsi nop timer setting, bad printks and session age testing. - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] scsi error: add target reset eh handler
From: Mike Christie <[EMAIL PROTECTED]> Drivers like qla4xxx and bnx2i (and it looks like some fcp drivers too), want to be able to send a lun reset in the eh device handler and then a target reset in some other handler. The old linux-iscsi driver, which did the host per session like open-iscsi did the target reset in the host reset, because the scsi command accounting that scsi_error.c does worked out nicely for software iscsi, but does not work for hardware iscsi well. This patch adds a eh_target_reset_handler any driver can use to send a target reset. The next patch will hook qla4xxx into it, and patches for iscsi_tcp/iser and bnx2i will follow later when bnx2i is closer to getting merged. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi_error.c | 121 ++--- include/scsi/scsi_eh.h|1 + include/scsi/scsi_host.h |1 + 3 files changed, 105 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 169bc59..fb1f5bc 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -524,6 +524,41 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) return rtn; } +static void __scsi_report_device_reset(struct scsi_device *sdev, void *data) +{ + sdev->was_reset = 1; + sdev->expecting_cc_ua = 1; +} + +/** + * scsi_try_target_reset - Ask host to perform a target reset + * @scmd: SCSI cmd used to send a target reset + * + * Notes: + *There is no timeout for this operation. if this operation is + *unreliable for a given host, then the host itself needs to put a + *timer on it, and set the host back to a consistent state prior to + *returning. + */ +static int scsi_try_target_reset(struct scsi_cmnd *scmd) +{ + unsigned long flags; + int rtn; + + if (!scmd->device->host->hostt->eh_target_reset_handler) + return FAILED; + + rtn = scmd->device->host->hostt->eh_target_reset_handler(scmd); + if (rtn == SUCCESS) { + spin_lock_irqsave(scmd->device->host->host_lock, flags); + __starget_for_each_device(scsi_target(scmd->device), NULL, + __scsi_report_device_reset); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + } + + return rtn; +} + /** * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev * @scmd: SCSI cmd used to send BDR @@ -542,11 +577,8 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) return FAILED; rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd); - if (rtn == SUCCESS) { - scmd->device->was_reset = 1; - scmd->device->expecting_cc_ua = 1; - } - + if (rtn == SUCCESS) + __scsi_report_device_reset(scmd->device, NULL); return rtn; } @@ -584,8 +616,9 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) { if (__scsi_try_to_abort_cmd(scmd) != SUCCESS) if (scsi_try_bus_device_reset(scmd) != SUCCESS) - if (scsi_try_bus_reset(scmd) != SUCCESS) - scsi_try_host_reset(scmd); + if (scsi_try_target_reset(scmd) != SUCCESS) + if (scsi_try_bus_reset(scmd) != SUCCESS) + scsi_try_host_reset(scmd); } /** @@ -1064,6 +1097,56 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, } /** + * scsi_eh_target_reset - send target reset if needed + * @shost: scsi host being recovered. + * @work_q: &list_head for pending commands. + * @done_q:&list_head for processed commands. + * + * Notes: + *Try a target reset. + */ +static int scsi_eh_target_reset(struct Scsi_Host *shost, + struct list_head *work_q, + struct list_head *done_q) +{ + struct scsi_cmnd *scmd, *tgtr_scmd, *next; + unsigned int id; + int rtn; + + for (id = 0; id <= shost->max_id; id++) { + tgtr_scmd = NULL; + list_for_each_entry(scmd, work_q, eh_entry) { + if (id == scmd_id(scmd)) { + tgtr_scmd = scmd; + break; + } + } + if (!tgtr_scmd) + continue; + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset " + "to target %d\n", + current->comm, id)); + rtn = scsi_try_target_reset(tgtr_scmd); + if (rtn == SUCCESS) { + list_for_each_entry_safe(scmd, next, work_q, eh_entry) { + if (id == scmd_id(scmd)) + if (!scsi_de
[PATCH 2/2] qla4xxx: Add target reset functionality
From: Mike Christie <[EMAIL PROTECTED]> This patch adds target reset functionalty. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/qla4xxx/ql4_fw.h |1 + drivers/scsi/qla4xxx/ql4_glbl.h |2 + drivers/scsi/qla4xxx/ql4_mbx.c | 39 drivers/scsi/qla4xxx/ql4_os.c | 74 ++- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index fe415ec..ed8ee66 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -216,6 +216,7 @@ union external_hw_config_reg { #define MBOX_CMD_ABOUT_FW 0x0009 #define MBOX_CMD_PING 0x000B #define MBOX_CMD_LUN_RESET 0x0016 +#define MBOX_CMD_TARGET_WARM_RESET 0x0017 #define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E #define MBOX_CMD_GET_FW_STATUS 0x001F #define MBOX_CMD_SET_ISNS_SERVICE 0x0021 diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index a3608e0..b403a17 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -27,6 +27,8 @@ int qla4xxx_relogin_device(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry); int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, int lun); +int qla4xxx_reset_target(struct scsi_qla_host * ha, +struct ddb_entry * ddb_entry); int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, uint32_t offset, uint32_t len); int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 35cd73c..c577d79 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -713,6 +713,45 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, return status; } +/** + * qla4xxx_reset_target - issues target Reset + * @ha: Pointer to host adapter structure. + * @db_entry: Pointer to device database entry + * @un_entry: Pointer to lun entry structure + * + * This routine performs a TARGET RESET on the specified target. + * The caller must ensure that the ddb_entry pointers + * are valid before calling this routine. + **/ +int qla4xxx_reset_target(struct scsi_qla_host *ha, +struct ddb_entry *ddb_entry) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + int status = QLA_SUCCESS; + + DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, + ddb_entry->os_target_id)); + + /* +* Send target reset command to ISP, so that the ISP will return all +* outstanding requests with RESET status +*/ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET; + mbox_cmd[1] = ddb_entry->fw_ddb_index; + mbox_cmd[5] = 0x01; /* Immediate Command Enable */ + + qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], + &mbox_sts[0]); + if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && + mbox_sts[0] != MBOX_STS_COMMAND_ERROR) + status = QLA_ERROR; + + return status; +} int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, uint32_t offset, uint32_t len) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index f55b9f7..05e6991 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -73,6 +73,7 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *)); static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); +static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); static int qla4xxx_slave_alloc(struct scsi_device *device); static int qla4xxx_slave_configure(struct scsi_device *device); @@ -85,6 +86,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .queuecommand = qla4xxx_queuecommand, .eh_device_reset_handler = qla4xxx_eh_device_reset, + .eh_target_reset_handler = qla4xxx_eh_target_reset, .eh_host_reset_handler = qla4xxx_eh_host_reset, .slave_configure= qla4xxx_slave_configure, @@ -1506,7 +1508,7 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) } /** - * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. + * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. * @ha: pointer to to HBA * @t: target id * @l: lun id @@ -1514,20 +1516,
RFC: add target reset handler to scsi_error.c
These patches add a target reset handler to scsi_error.c's error handler. It is needed because drivers like qla4xxx either have to do a target reset in the eh_device_reset_handler then do some tricks so that when that handler is called again we do not send extra resets, or the driver has to do its own loop in the bus or host reset handler that loops over the host's targets and sends a target reset for each target. Patches were made over scsi-misc. - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/24] iscsi_tcp, libiscsi: initial AHS Support
From: Mike Christie <[EMAIL PROTECTED]> at libiscsi generic code - currently code assumes a storage space of pdu header is allocated at llds ctask and is pointed to by iscsi_cmd_task->hdr. Here I add a hdr_max field pertaining to that storage, and an hdr_len that accumulates the current use of the pdu-header. - Add an iscsi_next_hdr() inline which returns the next free space to write new Header at. Also iscsi_next_hdr() is used to retrieve the address at which to write the header-digest. - Add iscsi_add_hdr(length). What the user do is calls iscsi_next_hdr() for address of the new header, than calls iscsi_add_hdr(length) with the size of the new header. iscsi_add_hdr() will check if space is available and update to the new size. length must be padded according to standard. - Add 2 padding inline helpers thanks to Olaf. Current patch does not use them but Following patches will. Also moved definition of ISCSI_PAD_LEN to iscsi_proto.h which had PAD_WORD_LEN that was never used anywhere. - Let iscsi_prep_scsi_cmd_pdu() signal an Error return since now it is possible that it will fail. - I was tired of yet again writing a "this is a digest" comment next to sizeof(__u32) so I defined a new ISCSI_DIGEST_SIZE. Now I don't need any comments. Changed all places that used sizeof(__u32) or "4" in connection to a digest. iscsi_tcp specific code - At struct iscsi_tcp_cmd_task allocate maximum space allowed in standard for all headers following the iscsi_cmd header. and mark it so in iscsi_tcp_session_create() - At iscsi_send_cmd_hdr() retrieve the correct headers size and write header digest at iscsi_next_hdr(). Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]> Acked-by: Olaf Kirch <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 16 drivers/scsi/iscsi_tcp.h | 13 +++-- drivers/scsi/libiscsi.c| 41 +++-- include/scsi/iscsi_proto.h | 10 +- include/scsi/libiscsi.h| 33 +++-- 5 files changed, 94 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index fd88777..491845f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -113,7 +113,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf, struct iscsi_tcp_conn *tcp_conn = conn->dd_data; crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc); - buf->sg.length += sizeof(u32); + buf->sg.length += ISCSI_DIGEST_SIZE; } /* @@ -220,6 +220,7 @@ static inline int iscsi_tcp_chunk_done(struct iscsi_chunk *chunk) { static unsigned char padbuf[ISCSI_PAD_LEN]; + unsigned int pad; if (chunk->copied < chunk->size) { iscsi_tcp_chunk_map(chunk); @@ -243,10 +244,8 @@ iscsi_tcp_chunk_done(struct iscsi_chunk *chunk) } /* Do we need to handle padding? */ - if (chunk->total_copied & (ISCSI_PAD_LEN-1)) { - unsigned int pad; - - pad = ISCSI_PAD_LEN - (chunk->total_copied & (ISCSI_PAD_LEN-1)); + pad = iscsi_padding(chunk->total_copied); + if (pad != 0) { debug_tcp("consume %d pad bytes\n", pad); chunk->total_size += pad; chunk->size = pad; @@ -1385,11 +1384,11 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr, - sizeof(struct iscsi_hdr)); + ctask->hdr_len); if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &tcp_ctask->headbuf, -(u8*)tcp_ctask->hdrext); +iscsi_next_hdr(ctask)); tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT; tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT; } @@ -2176,7 +2175,8 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - ctask->hdr = &tcp_ctask->hdr; + ctask->hdr = &tcp_ctask->hdr.cmd_hdr; + ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE; } for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index f1c5411..eb3784f 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -41,7 +41,6 @@ #define XMSTATE_IMM_HDR_INIT 0x1000 #define XMSTATE_SOL_HDR_INIT 0x2000 -#define ISCSI_PAD_LEN 4 #define ISCSI_SG_TABLESIZE SG_ALL #define ISCSI_TCP_MAX_CMD_LEN
[PATCH 05/24] iser patching for AHS support
From: Mike Christie <[EMAIL PROTECTED]> from Boaz Harrosh <[EMAIL PROTECTED]> - The default initialization of hdr_max is the minimum - sizeof(struct iscsi_cmd) - Once this patch goes into iser the default initialization at libiscsi can be removed. - This is not yet full support for AHSs at iser end. But it should be easy. Just allocate more space at iser_desc right after iscsi_hdr. Than at transmission time use ctask->hdr_len to retrieve the total size of all iscsi pdu headers. See previous patch at iscsi_tcp.[ch] Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/infiniband/ulp/iser/iscsi_iser.c |1 + drivers/scsi/libiscsi.c |1 - 2 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 2eadb6d..a2622f4 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -400,6 +400,7 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit, ctask = session->cmds[i]; iser_ctask = ctask->dd_data; ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header; + ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header); } for (i = 0; i < session->mgmtpool_max; i++) { diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 0d7914f..5936586 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1570,7 +1570,6 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (cmd_task_size) ctask->dd_data = &ctask[1]; ctask->itt = cmd_i; - ctask->hdr_max = sizeof(struct iscsi_cmd); INIT_LIST_HEAD(&ctask->running); } -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/24] Prettify resid handling and some extra checks
From: Mike Christie <[EMAIL PROTECTED]> from Boaz Harrosh: - Check to see that OVERFLOW is not negative indicating a bug. - Unify handling of UNDERFLOW and OVERFLOW to the same code. - Also handle BIDI_OVERFLOW. Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 16 +++- drivers/scsi/libiscsi.c | 12 +++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 1b540e0..fd88777 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -507,22 +507,20 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) { + sc->result = (DID_OK << 16) | rhdr->cmd_status; conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; - if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) { + if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW | + ISCSI_FLAG_DATA_OVERFLOW)) { int res_count = be32_to_cpu(rhdr->residual_count); if (res_count > 0 && - res_count <= scsi_bufflen(sc)) { + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || +res_count <= scsi_bufflen(sc))) scsi_set_resid(sc, res_count); - sc->result = (DID_OK << 16) | rhdr->cmd_status; - } else + else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) { - scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); - sc->result = (DID_OK << 16) | rhdr->cmd_status; - } else - sc->result = (DID_OK << 16) | rhdr->cmd_status; + } } conn->datain_pdus_cnt++; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 176458f..0beb4c6 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -291,17 +291,19 @@ invalid_datalen: min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); } - if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { + if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | + ISCSI_FLAG_CMD_OVERFLOW)) { int res_count = be32_to_cpu(rhdr->residual_count); - if (res_count > 0 && res_count <= scsi_bufflen(sc)) + if (res_count > 0 && + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || +res_count <= scsi_bufflen(sc))) scsi_set_resid(sc, res_count); else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) + } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | + ISCSI_FLAG_CMD_BIDI_OVERFLOW)) sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) - scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); out: debug_scsi("done [sc %lx res %d itt 0x%x]\n", -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/24] libiscsi, iscsi_tcp: iscsi pool cleanup
From: Mike Christie <[EMAIL PROTECTED]> from [EMAIL PROTECTED] iscsi_pool_init simplified iscsi_pool_init currently has a lot of duplicate kfree() calls it does when some allocation fails. This patch simplifies the code a little by using iscsi_pool_free to tear down the pool in case of an error. iscsi_pool_init also returns a copy of the item array to the caller. Not all callers use this array, so we make it optional. Instead of allocating a second array and return that, allocate just one array, of twice the size. Update users of iscsi_pool_{init,free} This patch drops the (now useless) second argument to iscsi_pool_free, and updates all callers. It also removes the ctask->r2ts array, which was never used anyway. Since the items argument to iscsi_pool_init is now optional, we can pass NULL instead. Signed-off-by: Olaf Kirch <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 12 ++- drivers/scsi/iscsi_tcp.h |3 +- drivers/scsi/libiscsi.c | 75 - include/scsi/libiscsi.h | 10 +++--- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 491845f..f79a457 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1998,8 +1998,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) */ /* R2T pool */ - if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, - (void***)&tcp_ctask->r2ts, + if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL, sizeof(struct iscsi_r2t_info))) { goto r2t_alloc_fail; } @@ -2008,8 +2007,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) tcp_ctask->r2tqueue = kfifo_alloc( session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) { - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); goto r2t_alloc_fail; } } @@ -2022,8 +2020,7 @@ r2t_alloc_fail: struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); } return -ENOMEM; } @@ -2038,8 +2035,7 @@ iscsi_r2tpool_free(struct iscsi_session *session) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); } } diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index eb3784f..d49d876 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -175,9 +175,8 @@ struct iscsi_tcp_cmd_task { uint32_texp_datasn; /* expected target's R2TSN/DataSN */ int data_offset; struct iscsi_r2t_info *r2t; /* in progress R2T*/ - struct iscsi_queue r2tpool; + struct iscsi_pool r2tpool; struct kfifo*r2tqueue; - struct iscsi_r2t_info **r2ts; int digest_count; uint32_timmdigest; /* for imm data */ struct iscsi_bufimmbuf; /* for imm data digest */ diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5936586..d43f909 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1413,59 +1413,64 @@ done: } EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); +/* + * Pre-allocate a pool of @max items of @item_size. By default, the pool + * should be accessed via kfifo_{get,put} on q->queue. + * Optionally, the caller can obtain the array of object pointers + * by passing in a non-NULL @items pointer + */ int -iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) +iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size) { - int i; + int i, num_arrays = 1; - *items = kmalloc(max * sizeof(void*), GFP_KERNEL); - if (*items == NULL) - return -ENOMEM; + memset(q, 0, sizeof(*q)); q->max = max; - q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL); - if (q->pool == NULL) { - kfree(*items); - return -ENOMEM; - } + + /* If the user passed an items pointer, he wants a copy of +* the array. */ +
[PATCH 02/24] iscsi_tcp: rewrite recv path
From: Mike Christie <[EMAIL PROTECTED]> >From Olaf Kirch: Rewrite recv path. Fixes: - data digest processing and error handling. - ahs support. Some fixups by Mike Christie Signed-off-by: [EMAIL PROTECTED] Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 1018 +++--- drivers/scsi/iscsi_tcp.h | 66 ++-- include/scsi/libiscsi.h |4 + 3 files changed, 552 insertions(+), 536 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 4b226b8..1b540e0 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov <[EMAIL PROTECTED]>, " "Alex Aizman <[EMAIL PROTECTED]>"); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -/* #define DEBUG_TCP */ +#undef DEBUG_TCP #define DEBUG_ASSERT #ifdef DEBUG_TCP @@ -67,10 +67,15 @@ MODULE_LICENSE("GPL"); static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); +static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_chunk *chunk); + static inline void iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) { - sg_init_one(&ibuf->sg, vbuf, size); + ibuf->sg.page = virt_to_page(vbuf); + ibuf->sg.offset = offset_in_page(vbuf); + ibuf->sg.length = size; ibuf->sent = 0; ibuf->use_sendmsg = 1; } @@ -78,12 +83,13 @@ iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) static inline void iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) { - sg_init_table(&ibuf->sg, 1); - sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset); + ibuf->sg.page = sg->page; + ibuf->sg.offset = sg->offset; + ibuf->sg.length = sg->length; /* * Fastpath: sg element fits into single page */ - if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg))) + if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page)) ibuf->use_sendmsg = 0; else ibuf->use_sendmsg = 1; @@ -110,72 +116,331 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf, buf->sg.length += sizeof(u32); } +/* + * Scatterlist handling: inside the iscsi_chunk, we + * remember an index into the scatterlist, and set data/size + * to the current scatterlist entry. For highmem pages, we + * kmap as needed. + * + * Note that the page is unmapped when we return from + * TCP's data_ready handler, so we may end up mapping and + * unmapping the same page repeatedly. The whole reason + * for this is that we shouldn't keep the page mapped + * outside the softirq. + */ + +/** + * iscsi_tcp_chunk_init_sg - init indicated scatterlist entry + * @chunk: the buffer object + * @idx: index into scatterlist + * @offset: byte offset into that sg entry + * + * This function sets up the chunk so that subsequent + * data is copied to the indicated sg entry, at the given + * offset. + */ +static inline void +iscsi_tcp_chunk_init_sg(struct iscsi_chunk *chunk, + unsigned int idx, unsigned int offset) +{ + struct scatterlist *sg; + + BUG_ON(chunk->sg == NULL); + + sg = &chunk->sg[idx]; + chunk->sg_index = idx; + chunk->sg_offset = offset; + chunk->size = min(sg->length - offset, chunk->total_size); + chunk->data = NULL; +} + +/** + * iscsi_tcp_chunk_map - map the current S/G page + * @chunk: iscsi chunk + * + * We only need to possibly kmap data if scatter lists are being used, + * because the iscsi passthrough and internal IO paths will never use high + * mem pages. + */ +static inline void +iscsi_tcp_chunk_map(struct iscsi_chunk *chunk) +{ + struct scatterlist *sg; + + if (chunk->data != NULL || !chunk->sg) + return; + + sg = &chunk->sg[chunk->sg_index]; + BUG_ON(chunk->sg_mapped); + BUG_ON(sg->length == 0); + chunk->sg_mapped = kmap_atomic(sg->page, KM_SOFTIRQ0); + chunk->data = chunk->sg_mapped + sg->offset + chunk->sg_offset; +} + +static inline void +iscsi_tcp_chunk_unmap(struct iscsi_chunk *chunk) +{ + if (chunk->sg_mapped) { + kunmap_atomic(chunk->sg_mapped, KM_SOFTIRQ0); + chunk->sg_mapped = NULL; + chunk->data = NULL; + } +} + +/* + * Splice the digest buffer into the buffer + */ +static inline void +iscsi_tcp_chunk_splice_digest(struct iscsi_chunk *chunk, void *digest) +{ + chunk->data = digest; + chunk->digest_len = ISCSI_DIGEST_SIZE; + chunk->total_size += ISCSI_DIGEST_SIZE; + chunk->size = ISCSI_DIGEST_SIZE; + chunk->copied = 0; + chunk->sg = NULL; + chunk->sg_index = 0; + chunk->hash = NULL; +} + +/** + * iscsi_tcp_chunk_done - check whether the chunk is complete + * @chunk: iscsi chunk to check + * + * Check
[PATCH 17/24] iscsi_tcp: stop leaking r2t_info's when the incoming R2T is bad
From: Mike Christie <[EMAIL PROTECTED]> from [EMAIL PROTECTED]: iscsi_r2t_rsp checks the incoming R2T for sanity, and if it thinks it's fishy, it will drop it silently. In this case, we leaked an r2t_info object. If we do this often enough, we run into a BUG_ON some time later. Removed r2t wrappers and update patch by Mike Christie Signed-off-by: Olaf Kirch <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |6 +- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7212fe9..ecba606 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -658,6 +658,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } @@ -669,10 +671,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - spin_unlock(&session->lock); printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " "offset %u and total length %d\n", r2t->data_length, r2t->data_offset, scsi_bufflen(ctask->sc)); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); + spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 24/24] iscsi class: bump version
From: Mike Christie <[EMAIL PROTECTED]> Update version. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi_transport_iscsi.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 3585599..ef0e742 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -33,7 +33,7 @@ #define ISCSI_SESSION_ATTRS 18 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-724" +#define ISCSI_TRANSPORT_VERSION "2.0-867" struct iscsi_internal { int daemon_pid; -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 22/24] libiscsi: use is_power_of_2
From: Mike Christie <[EMAIL PROTECTED]> Patch from vignesh babu <[EMAIL PROTECTED]>: Replacing n & (n - 1) for power of 2 check by is_power_of_2(n) Signed-off-by: vignesh babu <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 6573223..553168a 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1700,7 +1701,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, qdepth = ISCSI_DEF_CMD_PER_LUN; } - if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || + if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET) { if (cmds_max != 0) printk(KERN_ERR "iscsi: invalid can_queue of %d. " -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 23/24] iscsi_tcp: fix setting of r2t
From: Mike Christie <[EMAIL PROTECTED]> If we negotiate for X r2ts we have to use only X r2ts. We cannot round up (we could send less though). It is ok to fail if it is not something the driver can handle, so this patch just does that. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index edebdf2..e5be5fd 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1774,12 +1774,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, break; case ISCSI_PARAM_MAX_R2T: sscanf(buf, "%d", &value); - if (session->max_r2t == roundup_pow_of_two(value)) + if (value <= 0 || !is_power_of_2(value)) + return -EINVAL; + if (session->max_r2t == value) break; iscsi_r2tpool_free(session); iscsi_set_param(cls_conn, param, buf, buflen); - if (session->max_r2t & (session->max_r2t - 1)) - session->max_r2t = roundup_pow_of_two(session->max_r2t); if (iscsi_r2tpool_alloc(session)) return -ENOMEM; break; -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/24] iscsi_tcp: update the website URL
From: FUJITA Tomonori <[EMAIL PROTECTED]> Use open-iscsi.org instead of linux-iscsi.sf.net, which hasn't been updated for ages. Signed-off-by: FUJITA Tomonori <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/Kconfig |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index becbb09..4c7e99f 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -341,7 +341,7 @@ config ISCSI_TCP The userspace component needed to initialize the driver, documentation, and sample configuration files can be found here: -http://linux-iscsi.sf.net +http://open-iscsi.org config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver" -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 20/24] iscsi_tcp: enable sg chaining
From: Mike Christie <[EMAIL PROTECTED]> The previous patches converted iscsi_tcp to support sg chaining. This patch sets the proper flags and sets sg_table size to 4096. This allows fs io to be capped at max_sectors, but passthrough IO to be limited by some other part of the kernel. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |5 +++-- drivers/scsi/iscsi_tcp.h |3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 65df908..84c4a50 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1928,13 +1928,14 @@ static struct scsi_host_template iscsi_sht = { .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, - .sg_tablesize = ISCSI_SG_TABLESIZE, + .sg_tablesize = 4096, .max_sectors= 0x, .cmd_per_lun= ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler= iscsi_eh_device_reset, .eh_host_reset_handler = iscsi_eh_host_reset, .use_clustering = DISABLE_CLUSTERING, + .use_sg_chaining= ENABLE_SG_CHAINING, .slave_configure= iscsi_tcp_slave_configure, .proc_name = "iscsi_tcp", .this_id= -1, @@ -1974,7 +1975,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, - .max_cmd_len= ISCSI_TCP_MAX_CMD_LEN, + .max_cmd_len= 16, /* session management */ .create_session = iscsi_tcp_session_create, .destroy_session= iscsi_tcp_session_destroy, diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 893cd2e..ed0b991 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -24,9 +24,6 @@ #include -#define ISCSI_SG_TABLESIZE SG_ALL -#define ISCSI_TCP_MAX_CMD_LEN 16 - struct crypto_hash; struct socket; struct iscsi_tcp_conn; -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 21/24] iscsi_tcp: hold lock during data rsp processing
From: Mike Christie <[EMAIL PROTECTED]> iscsi_data_rsp needs to hold the sesison lock when it calls iscsi_update_cmdsn. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 14 ++ 1 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 84c4a50..edebdf2 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -641,13 +641,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } /* fill-in new R2T associated with the task */ - spin_lock(&session->lock); iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " "recovery...\n", ctask->itt); - spin_unlock(&session->lock); return 0; } @@ -660,7 +658,6 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); - spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } @@ -676,7 +673,6 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset, scsi_bufflen(ctask->sc)); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); - spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } @@ -690,8 +686,6 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) conn->r2t_pdus_cnt++; iscsi_requeue_ctask(ctask); - spin_unlock(&session->lock); - return 0; } @@ -764,7 +758,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) switch(opcode) { case ISCSI_OP_SCSI_DATA_IN: ctask = session->cmds[itt]; + spin_lock(&conn->session->lock); rc = iscsi_data_rsp(conn, ctask); + spin_unlock(&conn->session->lock); if (rc) return rc; if (tcp_conn->in.datalen) { @@ -806,9 +802,11 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) ctask = session->cmds[itt]; if (ahslen) rc = ISCSI_ERR_AHSLEN; - else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) + else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { + spin_lock(&session->lock); rc = iscsi_r2t_rsp(conn, ctask); - else + spin_unlock(&session->lock); + } else rc = ISCSI_ERR_PROTO; break; case ISCSI_OP_LOGIN_RSP: -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 18/24] iscsi_tcp: drop session when itt does not match any command
From: Mike Christie <[EMAIL PROTECTED]> A target should never send us a itt that does not match a running task. If it does we do not really know what is coming down after the header, unless we evaluate the hdr and do some guessing sometimes. However, even if we know what is coming we probably do not have buffers for it or we cannot respond (if it is a r2t for example), so just drop the session. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |6 +- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index ecba606..65df908 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -755,11 +755,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) opcode = hdr->opcode & ISCSI_OPCODE_MASK; /* verify itt (itt encoding: age+cid+itt) */ rc = iscsi_verify_itt(conn, hdr, &itt); - if (rc == ISCSI_ERR_NO_SCSI_CMD) { - /* XXX: what does this do? */ - tcp_conn->in.datalen = 0; /* force drop */ - return 0; - } else if (rc) + if (rc) return rc; debug_tcp("opcode 0x%x ahslen %d datalen %d\n", -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 19/24] libiscsi, iscsi class: set tmf to a safe default and export in sysfs
From: Mike Christie <[EMAIL PROTECTED]> Older tools will not be setting the tmf time outs since they did not exists, so set them to a safe default. And export abort and lu reset timeout values in sysfs. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |2 ++ drivers/scsi/scsi_transport_iscsi.c |8 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index f15df8d..6573223 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1732,6 +1732,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, session->host = shost; session->state = ISCSI_STATE_FREE; session->fast_abort = 1; + session->lu_reset_timeout = 15; + session->abort_timeout = 10; session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; session->cmds_max = cmds_max; session->queued_cmdsn = session->cmdsn = initial_cmdsn; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 36aa50e..3585599 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -30,7 +30,7 @@ #include #include -#define ISCSI_SESSION_ATTRS 16 +#define ISCSI_SESSION_ATTRS 18 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 4 #define ISCSI_TRANSPORT_VERSION "2.0-724" @@ -1242,7 +1242,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1); iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1); iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1); iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1); -iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 1); +iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); +iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); +iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); #define iscsi_priv_session_attr_show(field, format)\ static ssize_t \ @@ -1467,6 +1469,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD); SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN); SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); + SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); + SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); BUG_ON(count > ISCSI_SESSION_ATTRS); -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 14/24] clear conn->ctask when task is completed early
From: Mike Christie <[EMAIL PROTECTED]> If the current ctask is failed early, we legt the conn->ctask pointer pointing to a invalid task. When the xmit thread would send data for it, we would then oops. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |5 - 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index b17081b..4461317 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -248,13 +248,16 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) */ static void iscsi_complete_command(struct iscsi_cmd_task *ctask) { - struct iscsi_session *session = ctask->conn->session; + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = ctask->sc; ctask->state = ISCSI_TASK_COMPLETED; ctask->sc = NULL; /* SCSI eh reuses commands to verify us */ sc->SCp.ptr = NULL; + if (conn->ctask == ctask) + conn->ctask = NULL; list_del_init(&ctask->running); __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); sc->scsi_done(sc); -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 15/24] Drop host lock in queuecommand
From: Mike Christie <[EMAIL PROTECTED]> The driver does not need the host lock in queuecommand so drop it. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |6 +- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 4461317..b0bc8c3 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1010,8 +1010,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) sc->SCp.ptr = NULL; host = sc->device->host; - session = iscsi_hostdata(host->hostdata); + spin_unlock(host->host_lock); + session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); /* @@ -1077,11 +1078,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) spin_unlock(&session->lock); scsi_queue_work(host, &conn->xmitwork); + spin_lock(host->host_lock); return 0; reject: spin_unlock(&session->lock); debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); + spin_lock(host->host_lock); return SCSI_MLQUEUE_HOST_BUSY; fault: @@ -1091,6 +1094,7 @@ fault: sc->result = (DID_NO_CONNECT << 16); scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); + spin_lock(host->host_lock); return 0; } EXPORT_SYMBOL_GPL(iscsi_queuecommand); -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 13/24] Do not fail commands immediately during logout
From: Mike Christie <[EMAIL PROTECTED]> If the target requests a logout, then we do not want to fail commands to scsi-ml right away. This patch just fails in pending commands for a requeue immediately, and then lets iscsid handle running commands like normal recovery. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c | 14 ++ 1 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 9688361..b17081b 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -917,7 +917,7 @@ check_mgmt: conn->ctask = list_entry(conn->xmitqueue.next, struct iscsi_cmd_task, running); if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { - fail_command(conn, conn->ctask, DID_NO_CONNECT << 16); + fail_command(conn, conn->ctask, DID_IMM_RETRY << 16); continue; } if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { @@ -1024,21 +1024,19 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) * be entering our queuecommand while a block is starting * up because the block code is not locked) */ - if (session->state == ISCSI_STATE_IN_RECOVERY) { + switch (session->state) { + case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; goto reject; - } - - switch (session->state) { + case ISCSI_STATE_LOGGING_OUT: + reason = FAILURE_SESSION_LOGGING_OUT; + goto reject; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; break; case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; break; - case ISCSI_STATE_LOGGING_OUT: - reason = FAILURE_SESSION_LOGGING_OUT; - break; default: reason = FAILURE_SESSION_FREED; } -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/24] libiscsi: grab eh_mutex during host reset
From: Mike Christie <[EMAIL PROTECTED]> I thought we may not need the eh mutex during host reset, but that is wrong with the new shutdown code. When start_session_recovery sets the state to terminate then drops the session lock. The scsi eh thread could then grab the session lock see that we are terminating and then return failed to scsi-ml. scsi-ml's eh then owns the command and will do whatever it wants with it. But then the iscsi eh thread could grab the session lock and want to complete the scsi commands that we in the LLD, but it no longer owns them and kaboom. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |7 +-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index b7a2b9a..441e351 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1079,17 +1079,19 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) struct iscsi_session *session = iscsi_hostdata(host->hostdata); struct iscsi_conn *conn = session->leadconn; + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_TERMINATE) { failed: debug_scsi("failing host reset: session terminated " "[CID %d age %d]\n", conn->id, session->age); spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); return FAILED; } spin_unlock_bh(&session->lock); - + mutex_unlock(&session->eh_mutex); /* * we drop the lock here but the leadconn cannot be destoyed while * we are in the scsi eh @@ -1104,13 +1106,14 @@ failed: if (signal_pending(current)) flush_signals(current); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) printk(KERN_INFO "iscsi: host reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); - + mutex_unlock(&session->eh_mutex); return SUCCESS; } EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/24] libiscsi: fix nop handling
From: Mike Christie <[EMAIL PROTECTED]> During root boot and shutdown the target could send us nops. At this time iscsid cannot be running, so the target will drop the session and the boot or shutdown will hang. To handle this and allow us to better control when to check the network this patch moves the nop handling to the kernel. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/infiniband/ulp/iser/iscsi_iser.c |4 +- drivers/scsi/iscsi_tcp.c |4 +- drivers/scsi/libiscsi.c | 331 -- drivers/scsi/scsi_transport_iscsi.c |4 + include/scsi/iscsi_if.h | 11 + include/scsi/libiscsi.h |8 + 6 files changed, 294 insertions(+), 68 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index a2622f4..2656064 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -577,7 +577,9 @@ static struct iscsi_transport iscsi_iser_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | - ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO, .host_param_mask= ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME | ISCSI_HOST_INITIATOR_NAME, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 90eae8e..9b41852 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2246,7 +2246,9 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | - ISCSI_FAST_ABORT, + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_LU_RESET_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO, .host_param_mask= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME | ISCSI_HOST_NETDEV_NAME, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5205ef2..9688361 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -313,11 +313,70 @@ void iscsi_free_mgmt_task(struct iscsi_conn *conn, list_del_init(&mtask->running); if (conn->login_mtask == mtask) return; + + if (conn->ping_mtask == mtask) + conn->ping_mtask = NULL; __kfifo_put(conn->session->mgmtpool.queue, (void*)&mtask, sizeof(void*)); } EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); +static struct iscsi_mgmt_task * +__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size) +{ + struct iscsi_session *session = conn->session; + struct iscsi_mgmt_task *mtask; + + if (session->state == ISCSI_STATE_TERMINATE) + return NULL; + + if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || + hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) + /* +* Login and Text are sent serially, in +* request-followed-by-response sequence. +* Same mtask can be used. Same ITT must be used. +* Note that login_mtask is preallocated at conn_create(). +*/ + mtask = conn->login_mtask; + else { + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); + BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); + + if (!__kfifo_get(session->mgmtpool.queue, +(void*)&mtask, sizeof(void*))) + return NULL; + } + + if (data_size) { + memcpy(mtask->data, data, data_size); + mtask->data_count = data_size; + } else + mtask->data_count = 0; + + memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); + INIT_LIST_HEAD(&mtask->running); + list_add_tail(&mtask->running, &conn->mgmtqueue); + return mtask; +} + +int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + int err = 0; + + spin_lock_bh(&session->lock); + if (!
[PATCH 08/24] iscsi class: Use our own workq instead of common system one.
From: Mike Christie <[EMAIL PROTECTED]> There is just too much going on through the common workq and something like a scsi device removal through sysfs affects how long it will take to recover the transport, mark it as failed, or shut it down gracefully. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/scsi_transport_iscsi.c | 16 1 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 75d3069..9cc2cc8 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -50,6 +50,7 @@ struct iscsi_internal { }; static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ +static struct workqueue_struct *iscsi_eh_timer_workq; /* * list of registered transports and lock that must @@ -252,7 +253,7 @@ static void session_recovery_timedout(struct work_struct *work) void iscsi_unblock_session(struct iscsi_cls_session *session) { if (!cancel_delayed_work(&session->recovery_work)) - flush_scheduled_work(); + flush_workqueue(iscsi_eh_timer_workq); scsi_target_unblock(&session->dev); } EXPORT_SYMBOL_GPL(iscsi_unblock_session); @@ -260,8 +261,8 @@ EXPORT_SYMBOL_GPL(iscsi_unblock_session); void iscsi_block_session(struct iscsi_cls_session *session) { scsi_target_block(&session->dev); - schedule_delayed_work(&session->recovery_work, -session->recovery_tmo * HZ); + queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, + session->recovery_tmo * HZ); } EXPORT_SYMBOL_GPL(iscsi_block_session); @@ -357,7 +358,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) struct iscsi_host *ihost = shost->shost_data; if (!cancel_delayed_work(&session->recovery_work)) - flush_scheduled_work(); + flush_workqueue(iscsi_eh_timer_workq); mutex_lock(&ihost->mutex); list_del(&session->host_list); @@ -1521,8 +1522,14 @@ static __init int iscsi_transport_init(void) goto unregister_session_class; } + iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh"); + if (!iscsi_eh_timer_workq) + goto release_nls; + return 0; +release_nls: + sock_release(nls->sk_socket); unregister_session_class: transport_class_unregister(&iscsi_session_class); unregister_conn_class: @@ -1536,6 +1543,7 @@ unregister_transport_class: static void __exit iscsi_transport_exit(void) { + destroy_workqueue(iscsi_eh_timer_workq); sock_release(nls->sk_socket); transport_class_unregister(&iscsi_connection_class); transport_class_unregister(&iscsi_session_class); -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/24] libiscsi: fix shutdown
From: Mike Christie <[EMAIL PROTECTED]> We were using the device delete sysfs file to remove each device then logout. Now in 2.6.21 this will not work because the sysfs delete file returns immediately and does not wait for the device removal to complete. This causes a hang if a cache sync is needed during shutdown. Before .21, that approach had other problems, so this patch fixes the shutdown code so that we remove the target and unbind the session before logging out and shut down the session Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |4 +- drivers/scsi/qla4xxx/ql4_init.c |4 +- drivers/scsi/qla4xxx/ql4_os.c |7 +- drivers/scsi/scsi_transport_iscsi.c | 289 +++ include/scsi/iscsi_if.h |7 + include/scsi/iscsi_proto.h |2 + include/scsi/scsi_transport_iscsi.h |7 +- 7 files changed, 176 insertions(+), 144 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 441e351..5205ef2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1662,7 +1662,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) struct iscsi_session *session = iscsi_hostdata(shost->hostdata); struct module *owner = cls_session->transport->owner; - iscsi_unblock_session(cls_session); + iscsi_remove_session(cls_session); scsi_remove_host(shost); iscsi_pool_free(&session->mgmtpool); @@ -1677,7 +1677,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) kfree(session->hwaddress); kfree(session->initiatorname); - iscsi_destroy_session(cls_session); + iscsi_free_session(cls_session); scsi_host_put(shost); module_put(owner); } diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index d692c71..cbe0a17 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -5,6 +5,7 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ +#include #include "ql4_def.h" #include "ql4_glbl.h" #include "ql4_dbg.h" @@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); - iscsi_if_create_session_done(ddb_entry->conn); + iscsi_session_event(ddb_entry->sess, + ISCSI_KEVENT_CREATE_SESSION); /* * Change the lun state to READY in case the lun TIMEOUT before * the device came back. diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 89460d2..f55b9f7 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -298,8 +298,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) return; if (ddb_entry->conn) { - iscsi_if_destroy_session_done(ddb_entry->conn); - iscsi_destroy_conn(ddb_entry->conn); + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); iscsi_remove_session(ddb_entry->sess); } iscsi_free_session(ddb_entry->sess); @@ -309,6 +308,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) { int err; + ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); if (err) { DEBUG2(printk(KERN_ERR "Could not add session.\n")); @@ -321,9 +321,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) DEBUG2(printk(KERN_ERR "Could not add connection.\n")); return -ENOMEM; } - - ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; - iscsi_if_create_session_done(ddb_entry->conn); return 0; } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9cc2cc8..b82139d 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -116,6 +116,8 @@ static struct attribute_group iscsi_transport_group = { .attrs = iscsi_transport_attrs, }; + + static int iscsi_setup_host(struct transport_container *tc, struct device *dev, struct class_device *cdev) { @@ -125,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); + + snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", + shost->host_no); + ihost->unbind_workq = create_singlethread_workqueue( + ihost->unbind_workq_name); + if (!ihost->unbind_workq) +
[PATCH 07/24] libiscsi: do not block session during logout
From: Mike Christie <[EMAIL PROTECTED]> There is not need to block the session during logout. Since we are going to fail the commands that were blocked just fail them immediately instead. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/infiniband/ulp/iser/iser_initiator.c |4 +- drivers/scsi/iscsi_tcp.c |4 +- drivers/scsi/libiscsi.c | 153 ++ include/scsi/libiscsi.h |2 + include/scsi/scsi_transport_iscsi.h |1 + 5 files changed, 88 insertions(+), 76 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index a6f2303..47f716c 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc) struct iscsi_session *session = conn->session; spin_lock(&conn->session->lock); - list_del(&mtask->running); - __kfifo_put(session->mgmtpool.queue, (void*)&mtask, - sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); spin_unlock(&session->lock); } } diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index f79a457..90eae8e 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1349,9 +1349,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) struct iscsi_session *session = conn->session; spin_lock_bh(&session->lock); - list_del(&conn->mtask->running); - __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask, - sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); spin_unlock_bh(&session->lock); } return 0; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d43f909..b7a2b9a 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -37,9 +37,6 @@ #include #include -static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, -int err); - struct iscsi_session * class_to_transport_session(struct iscsi_cls_session *cls_session) { @@ -274,6 +271,53 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) iscsi_complete_command(ctask); } +/* + * session lock must be held + */ +static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, +int err) +{ + struct scsi_cmnd *sc; + + sc = ctask->sc; + if (!sc) + return; + + if (ctask->state == ISCSI_TASK_PENDING) + /* +* cmd never made it to the xmit thread, so we should not count +* the cmd in the sequencing +*/ + conn->session->queued_cmdsn--; + else + conn->session->tt->cleanup_cmd_task(conn, ctask); + + sc->result = err; + scsi_set_resid(sc, scsi_bufflen(sc)); + if (conn->ctask == ctask) + conn->ctask = NULL; + /* release ref from queuecommand */ + __iscsi_put_ctask(ctask); +} + +/** + * iscsi_free_mgmt_task - return mgmt task back to pool + * @conn: iscsi connection + * @mtask: mtask + * + * Must be called with session lock. + */ +void iscsi_free_mgmt_task(struct iscsi_conn *conn, + struct iscsi_mgmt_task *mtask) +{ + list_del_init(&mtask->running); + if (conn->login_mtask == mtask) + return; + __kfifo_put(conn->session->mgmtpool.queue, + (void*)&mtask, sizeof(void*)); +} +EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); + /** * iscsi_cmd_rsp - SCSI Command Response processing * @conn: iscsi connection @@ -464,10 +508,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, */ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) rc = ISCSI_ERR_CONN_FAILED; - list_del_init(&mtask->running); - if (conn->login_mtask != mtask) - __kfifo_put(session->mgmtpool.queue, - (void*)&mtask, sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); break; case ISCSI_OP_SCSI_TMFUNC_RSP: if (datalen) { @@ -476,6 +517,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } iscsi_tmf_rsp(conn, hdr); + iscsi_free_mgmt_task(conn, mtask); break; case ISCSI_OP_NOOP_IN:
[PATCH 01/24] libiscsi, iscsi_tcp: add device support
From: Mike Christie <[EMAIL PROTECTED]> This patch adds logical unit reset support. This should work for ib_iser, but I have not finished testing that driver so it is not hooked in yet. This patch also temporarily reverts the iscsi_tcp r2t write out patch. That code is completely rewritten in this patchset. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/infiniband/ulp/iser/iscsi_iser.c |6 - drivers/scsi/iscsi_tcp.c | 151 +- drivers/scsi/iscsi_tcp.h | 34 +- drivers/scsi/libiscsi.c | 494 +- drivers/scsi/scsi_transport_iscsi.c |4 +- include/scsi/iscsi_if.h |2 + include/scsi/iscsi_proto.h |2 + include/scsi/libiscsi.h | 25 +- 8 files changed, 396 insertions(+), 322 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index bad8dac..2eadb6d 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -220,12 +220,6 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn, debug_scsi("ctask deq [cid %d itt 0x%x]\n", conn->id, ctask->itt); - /* -* serialize with TMF AbortTask -*/ - if (ctask->mtask) - return error; - /* Send the cmd PDU */ if (!iser_ctask->command_sent) { error = iser_send_command(conn, ctask); diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 57ce225..4b226b8 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -197,7 +197,7 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) if (unlikely(!sc)) return; - tcp_ctask->xmstate = XMSTATE_VALUE_IDLE; + tcp_ctask->xmstate = XMSTATE_IDLE; tcp_ctask->r2t = NULL; } @@ -369,8 +369,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) spin_lock(&session->lock); iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (!ctask->sc || ctask->mtask || -session->state != ISCSI_STATE_LOGGED_IN) { + if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " "recovery...\n", ctask->itt); spin_unlock(&session->lock); @@ -409,11 +408,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn = r2tsn + 1; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); - set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate); - list_move_tail(&ctask->running, &conn->xmitqueue); - - scsi_queue_work(session->host, &conn->xmitwork); + tcp_ctask->xmstate |= XMSTATE_SOL_HDR_INIT; conn->r2t_pdus_cnt++; + + iscsi_requeue_ctask(ctask); spin_unlock(&session->lock); return 0; @@ -1254,7 +1252,7 @@ static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask, tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count; debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count); - set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate); + tcp_ctask->xmstate |= XMSTATE_W_PAD; } /** @@ -1269,7 +1267,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; BUG_ON(__kfifo_len(tcp_ctask->r2tqueue)); - tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT; + tcp_ctask->xmstate = XMSTATE_CMD_HDR_INIT; } /** @@ -1283,10 +1281,10 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) * xmit. * * Management xmit state machine consists of these states: - * XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header - * XMSTATE_BIT_IMM_HDR - PDU Header xmit in progress - * XMSTATE_BIT_IMM_DATA - PDU Data xmit in progress - * XMSTATE_VALUE_IDLE - management PDU is done + * XMSTATE_IMM_HDR_INIT- calculate digest of PDU Header + * XMSTATE_IMM_HDR - PDU Header xmit in progress + * XMSTATE_IMM_DATA- PDU Data xmit in progress + * XMSTATE_IDLE- management PDU is done **/ static int iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) @@ -1297,12 +1295,12 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n", conn->id, tcp_mtask->xmstate, mtask->itt); - if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) { + if (tcp_mtask->xmstate & XMSTATE_IMM_HDR_INIT) { iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr, sizeof(struct iscsi_hdr));
RESEND: iscsi update for 2.6.25
Between the time I made my last patchset and when James rebased scsi-misc a patch to scsi_transport_iscsi.c got merged and that broke my patchset. This is a resend of the patchset, but rebased against scsi-misc. Sorry for the bigger than normal update. There are patches from Olaf and Boaz which do the following: - Rewrite iscsi_tcp data path (from Olaf), so we do not have two ulgy abstractions for the send and recv path. Now we have one nice iscsi_segment struct that works for both paths. - Add basic iscsi spec handling we will need for Bidi support (from Boaz). This does not add bidi support. It just adds code that is common. - Device reset support. Some clustering software needed at least device reset support, so I cleaned up that code and added device logical unit reset support. I will add warm target reset support later. - Lots of fixes for things like shutdown, r2t leaks, and lots of clean up from Olaf. - sg chaining support. - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 05/23] iser patching for AHS support
From: Mike Christie <[EMAIL PROTECTED]> from Boaz Harrosh <[EMAIL PROTECTED]> - The default initialization of hdr_max is the minimum - sizeof(struct iscsi_cmd) - Once this patch goes into iser the default initialization at libiscsi can be removed. - This is not yet full support for AHSs at iser end. But it should be easy. Just allocate more space at iser_desc right after iscsi_hdr. Than at transmission time use ctask->hdr_len to retrieve the total size of all iscsi pdu headers. See previous patch at iscsi_tcp.[ch] Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/infiniband/ulp/iser/iscsi_iser.c |1 + drivers/scsi/libiscsi.c |1 - 2 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 2eadb6d..a2622f4 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -400,6 +400,7 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit, ctask = session->cmds[i]; iser_ctask = ctask->dd_data; ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header; + ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header); } for (i = 0; i < session->mgmtpool_max; i++) { diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 0d7914f..5936586 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1570,7 +1570,6 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (cmd_task_size) ctask->dd_data = &ctask[1]; ctask->itt = cmd_i; - ctask->hdr_max = sizeof(struct iscsi_cmd); INIT_LIST_HEAD(&ctask->running); } -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 17/23] iscsi_tcp: stop leaking r2t_info's when the incoming R2T is bad
From: Mike Christie <[EMAIL PROTECTED]> from [EMAIL PROTECTED]: iscsi_r2t_rsp checks the incoming R2T for sanity, and if it thinks it's fishy, it will drop it silently. In this case, we leaked an r2t_info object. If we do this often enough, we run into a BUG_ON some time later. Removed r2t wrappers and update patch by Mike Christie Signed-off-by: Olaf Kirch <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |6 +- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7212fe9..ecba606 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -658,6 +658,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } @@ -669,10 +671,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - spin_unlock(&session->lock); printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " "offset %u and total length %d\n", r2t->data_length, r2t->data_offset, scsi_bufflen(ctask->sc)); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); + spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/23] iscsi_tcp, libiscsi: initial AHS Support
From: Mike Christie <[EMAIL PROTECTED]> at libiscsi generic code - currently code assumes a storage space of pdu header is allocated at llds ctask and is pointed to by iscsi_cmd_task->hdr. Here I add a hdr_max field pertaining to that storage, and an hdr_len that accumulates the current use of the pdu-header. - Add an iscsi_next_hdr() inline which returns the next free space to write new Header at. Also iscsi_next_hdr() is used to retrieve the address at which to write the header-digest. - Add iscsi_add_hdr(length). What the user do is calls iscsi_next_hdr() for address of the new header, than calls iscsi_add_hdr(length) with the size of the new header. iscsi_add_hdr() will check if space is available and update to the new size. length must be padded according to standard. - Add 2 padding inline helpers thanks to Olaf. Current patch does not use them but Following patches will. Also moved definition of ISCSI_PAD_LEN to iscsi_proto.h which had PAD_WORD_LEN that was never used anywhere. - Let iscsi_prep_scsi_cmd_pdu() signal an Error return since now it is possible that it will fail. - I was tired of yet again writing a "this is a digest" comment next to sizeof(__u32) so I defined a new ISCSI_DIGEST_SIZE. Now I don't need any comments. Changed all places that used sizeof(__u32) or "4" in connection to a digest. iscsi_tcp specific code - At struct iscsi_tcp_cmd_task allocate maximum space allowed in standard for all headers following the iscsi_cmd header. and mark it so in iscsi_tcp_session_create() - At iscsi_send_cmd_hdr() retrieve the correct headers size and write header digest at iscsi_next_hdr(). Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]> Acked-by: Olaf Kirch <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 16 drivers/scsi/iscsi_tcp.h | 13 +++-- drivers/scsi/libiscsi.c| 41 +++-- include/scsi/iscsi_proto.h | 10 +- include/scsi/libiscsi.h| 33 +++-- 5 files changed, 94 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index fd88777..491845f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -113,7 +113,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf, struct iscsi_tcp_conn *tcp_conn = conn->dd_data; crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc); - buf->sg.length += sizeof(u32); + buf->sg.length += ISCSI_DIGEST_SIZE; } /* @@ -220,6 +220,7 @@ static inline int iscsi_tcp_chunk_done(struct iscsi_chunk *chunk) { static unsigned char padbuf[ISCSI_PAD_LEN]; + unsigned int pad; if (chunk->copied < chunk->size) { iscsi_tcp_chunk_map(chunk); @@ -243,10 +244,8 @@ iscsi_tcp_chunk_done(struct iscsi_chunk *chunk) } /* Do we need to handle padding? */ - if (chunk->total_copied & (ISCSI_PAD_LEN-1)) { - unsigned int pad; - - pad = ISCSI_PAD_LEN - (chunk->total_copied & (ISCSI_PAD_LEN-1)); + pad = iscsi_padding(chunk->total_copied); + if (pad != 0) { debug_tcp("consume %d pad bytes\n", pad); chunk->total_size += pad; chunk->size = pad; @@ -1385,11 +1384,11 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr, - sizeof(struct iscsi_hdr)); + ctask->hdr_len); if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &tcp_ctask->headbuf, -(u8*)tcp_ctask->hdrext); +iscsi_next_hdr(ctask)); tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT; tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT; } @@ -2176,7 +2175,8 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - ctask->hdr = &tcp_ctask->hdr; + ctask->hdr = &tcp_ctask->hdr.cmd_hdr; + ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE; } for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index f1c5411..eb3784f 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -41,7 +41,6 @@ #define XMSTATE_IMM_HDR_INIT 0x1000 #define XMSTATE_SOL_HDR_INIT 0x2000 -#define ISCSI_PAD_LEN 4 #define ISCSI_SG_TABLESIZE SG_ALL #define ISCSI_TCP_MAX_CMD_LEN
[PATCH 12/23] iscsi_tcp: update the website URL
From: FUJITA Tomonori <[EMAIL PROTECTED]> Use open-iscsi.org instead of linux-iscsi.sf.net, which hasn't been updated for ages. Signed-off-by: FUJITA Tomonori <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/Kconfig |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index a6676be..ab965f5 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -341,7 +341,7 @@ config ISCSI_TCP The userspace component needed to initialize the driver, documentation, and sample configuration files can be found here: -http://linux-iscsi.sf.net +http://open-iscsi.org config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver" -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/23] Prettify resid handling and some extra checks
From: Mike Christie <[EMAIL PROTECTED]> from Boaz Harrosh: - Check to see that OVERFLOW is not negative indicating a bug. - Unify handling of UNDERFLOW and OVERFLOW to the same code. - Also handle BIDI_OVERFLOW. Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 16 +++- drivers/scsi/libiscsi.c | 12 +++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 1b540e0..fd88777 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -507,22 +507,20 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) { + sc->result = (DID_OK << 16) | rhdr->cmd_status; conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; - if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) { + if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW | + ISCSI_FLAG_DATA_OVERFLOW)) { int res_count = be32_to_cpu(rhdr->residual_count); if (res_count > 0 && - res_count <= scsi_bufflen(sc)) { + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || +res_count <= scsi_bufflen(sc))) scsi_set_resid(sc, res_count); - sc->result = (DID_OK << 16) | rhdr->cmd_status; - } else + else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) { - scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); - sc->result = (DID_OK << 16) | rhdr->cmd_status; - } else - sc->result = (DID_OK << 16) | rhdr->cmd_status; + } } conn->datain_pdus_cnt++; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 176458f..0beb4c6 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -291,17 +291,19 @@ invalid_datalen: min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); } - if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { + if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | + ISCSI_FLAG_CMD_OVERFLOW)) { int res_count = be32_to_cpu(rhdr->residual_count); - if (res_count > 0 && res_count <= scsi_bufflen(sc)) + if (res_count > 0 && + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || +res_count <= scsi_bufflen(sc))) scsi_set_resid(sc, res_count); else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) + } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | + ISCSI_FLAG_CMD_BIDI_OVERFLOW)) sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) - scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); out: debug_scsi("done [sc %lx res %d itt 0x%x]\n", -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 22/23] libiscsi: use is_power_of_2
From: Mike Christie <[EMAIL PROTECTED]> Patch from vignesh babu <[EMAIL PROTECTED]>: Replacing n & (n - 1) for power of 2 check by is_power_of_2(n) Signed-off-by: vignesh babu <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 6573223..553168a 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1700,7 +1701,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, qdepth = ISCSI_DEF_CMD_PER_LUN; } - if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || + if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET) { if (cmds_max != 0) printk(KERN_ERR "iscsi: invalid can_queue of %d. " -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 23/23] iscsi_tcp: fix setting of r2t
From: Mike Christie <[EMAIL PROTECTED]> If we negotiate for X r2ts we have to use only X r2ts. We cannot round up (we could send less though). It is ok to fail if it is not something the driver can handle, so this patch just does that. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index edebdf2..e5be5fd 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1774,12 +1774,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, break; case ISCSI_PARAM_MAX_R2T: sscanf(buf, "%d", &value); - if (session->max_r2t == roundup_pow_of_two(value)) + if (value <= 0 || !is_power_of_2(value)) + return -EINVAL; + if (session->max_r2t == value) break; iscsi_r2tpool_free(session); iscsi_set_param(cls_conn, param, buf, buflen); - if (session->max_r2t & (session->max_r2t - 1)) - session->max_r2t = roundup_pow_of_two(session->max_r2t); if (iscsi_r2tpool_alloc(session)) return -ENOMEM; break; -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 20/23] iscsi_tcp: enable sg chaining
From: Mike Christie <[EMAIL PROTECTED]> The previous patches converted iscsi_tcp to support sg chaining. This patch sets the proper flags and sets sg_table size to 4096. This allows fs io to be capped at max_sectors, but passthrough IO to be limited by some other part of the kernel. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |5 +++-- drivers/scsi/iscsi_tcp.h |3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 65df908..84c4a50 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1928,13 +1928,14 @@ static struct scsi_host_template iscsi_sht = { .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, - .sg_tablesize = ISCSI_SG_TABLESIZE, + .sg_tablesize = 4096, .max_sectors= 0x, .cmd_per_lun= ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler= iscsi_eh_device_reset, .eh_host_reset_handler = iscsi_eh_host_reset, .use_clustering = DISABLE_CLUSTERING, + .use_sg_chaining= ENABLE_SG_CHAINING, .slave_configure= iscsi_tcp_slave_configure, .proc_name = "iscsi_tcp", .this_id= -1, @@ -1974,7 +1975,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, - .max_cmd_len= ISCSI_TCP_MAX_CMD_LEN, + .max_cmd_len= 16, /* session management */ .create_session = iscsi_tcp_session_create, .destroy_session= iscsi_tcp_session_destroy, diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 893cd2e..ed0b991 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -24,9 +24,6 @@ #include -#define ISCSI_SG_TABLESIZE SG_ALL -#define ISCSI_TCP_MAX_CMD_LEN 16 - struct crypto_hash; struct socket; struct iscsi_tcp_conn; -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 21/23] iscsi_tcp: hold lock during data rsp processing
From: Mike Christie <[EMAIL PROTECTED]> iscsi_data_rsp needs to hold the sesison lock when it calls iscsi_update_cmdsn. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 14 ++ 1 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 84c4a50..edebdf2 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -641,13 +641,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } /* fill-in new R2T associated with the task */ - spin_lock(&session->lock); iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " "recovery...\n", ctask->itt); - spin_unlock(&session->lock); return 0; } @@ -660,7 +658,6 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); - spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } @@ -676,7 +673,6 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset, scsi_bufflen(ctask->sc)); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); - spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } @@ -690,8 +686,6 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) conn->r2t_pdus_cnt++; iscsi_requeue_ctask(ctask); - spin_unlock(&session->lock); - return 0; } @@ -764,7 +758,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) switch(opcode) { case ISCSI_OP_SCSI_DATA_IN: ctask = session->cmds[itt]; + spin_lock(&conn->session->lock); rc = iscsi_data_rsp(conn, ctask); + spin_unlock(&conn->session->lock); if (rc) return rc; if (tcp_conn->in.datalen) { @@ -806,9 +802,11 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) ctask = session->cmds[itt]; if (ahslen) rc = ISCSI_ERR_AHSLEN; - else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) + else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { + spin_lock(&session->lock); rc = iscsi_r2t_rsp(conn, ctask); - else + spin_unlock(&session->lock); + } else rc = ISCSI_ERR_PROTO; break; case ISCSI_OP_LOGIN_RSP: -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 18/23] iscsi_tcp: drop session when itt does not match any command
From: Mike Christie <[EMAIL PROTECTED]> A target should never send us a itt that does not match a running task. If it does we do not really know what is coming down after the header, unless we evaluate the hdr and do some guessing sometimes. However, even if we know what is coming we probably do not have buffers for it or we cannot respond (if it is a r2t for example), so just drop the session. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c |6 +- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index ecba606..65df908 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -755,11 +755,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) opcode = hdr->opcode & ISCSI_OPCODE_MASK; /* verify itt (itt encoding: age+cid+itt) */ rc = iscsi_verify_itt(conn, hdr, &itt); - if (rc == ISCSI_ERR_NO_SCSI_CMD) { - /* XXX: what does this do? */ - tcp_conn->in.datalen = 0; /* force drop */ - return 0; - } else if (rc) + if (rc) return rc; debug_tcp("opcode 0x%x ahslen %d datalen %d\n", -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 19/23] libiscsi, iscsi class: set tmf to a safe default and export in sysfs
From: Mike Christie <[EMAIL PROTECTED]> Older tools will not be setting the tmf time outs since they did not exists, so set them to a safe default. And export abort and lu reset timeout values in sysfs. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |2 ++ drivers/scsi/scsi_transport_iscsi.c |8 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index f15df8d..6573223 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1732,6 +1732,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, session->host = shost; session->state = ISCSI_STATE_FREE; session->fast_abort = 1; + session->lu_reset_timeout = 15; + session->abort_timeout = 10; session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; session->cmds_max = cmds_max; session->queued_cmdsn = session->cmdsn = initial_cmdsn; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index fb8a765..d3db318 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -30,7 +30,7 @@ #include #include -#define ISCSI_SESSION_ATTRS 16 +#define ISCSI_SESSION_ATTRS 18 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 4 #define ISCSI_TRANSPORT_VERSION "2.0-724" @@ -1241,7 +1241,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1); iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1); iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1); iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1); -iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 1); +iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); +iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); +iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); #define iscsi_priv_session_attr_show(field, format)\ static ssize_t \ @@ -1466,6 +1468,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD); SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN); SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); + SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); + SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); BUG_ON(count > ISCSI_SESSION_ATTRS); -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/23] libiscsi, iscsi_tcp: iscsi pool cleanup
From: Mike Christie <[EMAIL PROTECTED]> from [EMAIL PROTECTED] iscsi_pool_init simplified iscsi_pool_init currently has a lot of duplicate kfree() calls it does when some allocation fails. This patch simplifies the code a little by using iscsi_pool_free to tear down the pool in case of an error. iscsi_pool_init also returns a copy of the item array to the caller. Not all callers use this array, so we make it optional. Instead of allocating a second array and return that, allocate just one array, of twice the size. Update users of iscsi_pool_{init,free} This patch drops the (now useless) second argument to iscsi_pool_free, and updates all callers. It also removes the ctask->r2ts array, which was never used anyway. Since the items argument to iscsi_pool_init is now optional, we can pass NULL instead. Signed-off-by: Olaf Kirch <[EMAIL PROTECTED]> Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 12 ++- drivers/scsi/iscsi_tcp.h |3 +- drivers/scsi/libiscsi.c | 75 - include/scsi/libiscsi.h | 10 +++--- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 491845f..f79a457 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1998,8 +1998,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) */ /* R2T pool */ - if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, - (void***)&tcp_ctask->r2ts, + if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL, sizeof(struct iscsi_r2t_info))) { goto r2t_alloc_fail; } @@ -2008,8 +2007,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) tcp_ctask->r2tqueue = kfifo_alloc( session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) { - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); goto r2t_alloc_fail; } } @@ -2022,8 +2020,7 @@ r2t_alloc_fail: struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); } return -ENOMEM; } @@ -2038,8 +2035,7 @@ iscsi_r2tpool_free(struct iscsi_session *session) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); } } diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index eb3784f..d49d876 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -175,9 +175,8 @@ struct iscsi_tcp_cmd_task { uint32_texp_datasn; /* expected target's R2TSN/DataSN */ int data_offset; struct iscsi_r2t_info *r2t; /* in progress R2T*/ - struct iscsi_queue r2tpool; + struct iscsi_pool r2tpool; struct kfifo*r2tqueue; - struct iscsi_r2t_info **r2ts; int digest_count; uint32_timmdigest; /* for imm data */ struct iscsi_bufimmbuf; /* for imm data digest */ diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5936586..d43f909 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1413,59 +1413,64 @@ done: } EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); +/* + * Pre-allocate a pool of @max items of @item_size. By default, the pool + * should be accessed via kfifo_{get,put} on q->queue. + * Optionally, the caller can obtain the array of object pointers + * by passing in a non-NULL @items pointer + */ int -iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) +iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size) { - int i; + int i, num_arrays = 1; - *items = kmalloc(max * sizeof(void*), GFP_KERNEL); - if (*items == NULL) - return -ENOMEM; + memset(q, 0, sizeof(*q)); q->max = max; - q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL); - if (q->pool == NULL) { - kfree(*items); - return -ENOMEM; - } + + /* If the user passed an items pointer, he wants a copy of +* the array. */ +
[PATCH 02/23] iscsi_tcp: rewrite recv path
From: Mike Christie <[EMAIL PROTECTED]> >From Olaf Kirch: Rewrite recv path. Fixes: - data digest processing and error handling. - ahs support. Some fixups by Mike Christie Signed-off-by: [EMAIL PROTECTED] Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/iscsi_tcp.c | 1018 +++--- drivers/scsi/iscsi_tcp.h | 66 ++-- include/scsi/libiscsi.h |4 + 3 files changed, 552 insertions(+), 536 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 4b226b8..1b540e0 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov <[EMAIL PROTECTED]>, " "Alex Aizman <[EMAIL PROTECTED]>"); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -/* #define DEBUG_TCP */ +#undef DEBUG_TCP #define DEBUG_ASSERT #ifdef DEBUG_TCP @@ -67,10 +67,15 @@ MODULE_LICENSE("GPL"); static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); +static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_chunk *chunk); + static inline void iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) { - sg_init_one(&ibuf->sg, vbuf, size); + ibuf->sg.page = virt_to_page(vbuf); + ibuf->sg.offset = offset_in_page(vbuf); + ibuf->sg.length = size; ibuf->sent = 0; ibuf->use_sendmsg = 1; } @@ -78,12 +83,13 @@ iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) static inline void iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) { - sg_init_table(&ibuf->sg, 1); - sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset); + ibuf->sg.page = sg->page; + ibuf->sg.offset = sg->offset; + ibuf->sg.length = sg->length; /* * Fastpath: sg element fits into single page */ - if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg))) + if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page)) ibuf->use_sendmsg = 0; else ibuf->use_sendmsg = 1; @@ -110,72 +116,331 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf, buf->sg.length += sizeof(u32); } +/* + * Scatterlist handling: inside the iscsi_chunk, we + * remember an index into the scatterlist, and set data/size + * to the current scatterlist entry. For highmem pages, we + * kmap as needed. + * + * Note that the page is unmapped when we return from + * TCP's data_ready handler, so we may end up mapping and + * unmapping the same page repeatedly. The whole reason + * for this is that we shouldn't keep the page mapped + * outside the softirq. + */ + +/** + * iscsi_tcp_chunk_init_sg - init indicated scatterlist entry + * @chunk: the buffer object + * @idx: index into scatterlist + * @offset: byte offset into that sg entry + * + * This function sets up the chunk so that subsequent + * data is copied to the indicated sg entry, at the given + * offset. + */ +static inline void +iscsi_tcp_chunk_init_sg(struct iscsi_chunk *chunk, + unsigned int idx, unsigned int offset) +{ + struct scatterlist *sg; + + BUG_ON(chunk->sg == NULL); + + sg = &chunk->sg[idx]; + chunk->sg_index = idx; + chunk->sg_offset = offset; + chunk->size = min(sg->length - offset, chunk->total_size); + chunk->data = NULL; +} + +/** + * iscsi_tcp_chunk_map - map the current S/G page + * @chunk: iscsi chunk + * + * We only need to possibly kmap data if scatter lists are being used, + * because the iscsi passthrough and internal IO paths will never use high + * mem pages. + */ +static inline void +iscsi_tcp_chunk_map(struct iscsi_chunk *chunk) +{ + struct scatterlist *sg; + + if (chunk->data != NULL || !chunk->sg) + return; + + sg = &chunk->sg[chunk->sg_index]; + BUG_ON(chunk->sg_mapped); + BUG_ON(sg->length == 0); + chunk->sg_mapped = kmap_atomic(sg->page, KM_SOFTIRQ0); + chunk->data = chunk->sg_mapped + sg->offset + chunk->sg_offset; +} + +static inline void +iscsi_tcp_chunk_unmap(struct iscsi_chunk *chunk) +{ + if (chunk->sg_mapped) { + kunmap_atomic(chunk->sg_mapped, KM_SOFTIRQ0); + chunk->sg_mapped = NULL; + chunk->data = NULL; + } +} + +/* + * Splice the digest buffer into the buffer + */ +static inline void +iscsi_tcp_chunk_splice_digest(struct iscsi_chunk *chunk, void *digest) +{ + chunk->data = digest; + chunk->digest_len = ISCSI_DIGEST_SIZE; + chunk->total_size += ISCSI_DIGEST_SIZE; + chunk->size = ISCSI_DIGEST_SIZE; + chunk->copied = 0; + chunk->sg = NULL; + chunk->sg_index = 0; + chunk->hash = NULL; +} + +/** + * iscsi_tcp_chunk_done - check whether the chunk is complete + * @chunk: iscsi chunk to check + * + * Check
[PATCH 15/23] Drop host lock in queuecommand
From: Mike Christie <[EMAIL PROTECTED]> The driver does not need the host lock in queuecommand so drop it. Signed-off-by: Mike Christie <[EMAIL PROTECTED]> --- drivers/scsi/libiscsi.c |6 +- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 4461317..b0bc8c3 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1010,8 +1010,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) sc->SCp.ptr = NULL; host = sc->device->host; - session = iscsi_hostdata(host->hostdata); + spin_unlock(host->host_lock); + session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); /* @@ -1077,11 +1078,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) spin_unlock(&session->lock); scsi_queue_work(host, &conn->xmitwork); + spin_lock(host->host_lock); return 0; reject: spin_unlock(&session->lock); debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); + spin_lock(host->host_lock); return SCSI_MLQUEUE_HOST_BUSY; fault: @@ -1091,6 +1094,7 @@ fault: sc->result = (DID_NO_CONNECT << 16); scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); + spin_lock(host->host_lock); return 0; } EXPORT_SYMBOL_GPL(iscsi_queuecommand); -- 1.5.1.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html