Browse Source

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

* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (59 commits)
  [SCSI] replace __FUNCTION__ with __func__
  [SCSI] extend the last_sector_bug flag to cover more sectors
  [SCSI] qla2xxx: Update version number to 8.02.01-k6.
  [SCSI] qla2xxx: Additional NPIV corrections.
  [SCSI] qla2xxx: suppress uninitialized-var warning
  [SCSI] qla2xxx: use memory_read_from_buffer()
  [SCSI] qla2xxx: Issue proper ISP callbacks during stop-firmware.
  [SCSI] ch: fix ch_remove oops
  [SCSI] 3w-9xxx: add MSI support and misc fixes
  [SCSI] scsi_lib: use blk_rq_tagged in scsi_request_fn
  [SCSI] ibmvfc: Update driver version to 1.0.1
  [SCSI] ibmvfc: Add ADISC support
  [SCSI] ibmvfc: Miscellaneous fixes
  [SCSI] ibmvfc: Fix hang on module removal
  [SCSI] ibmvfc: Target refcounting fixes
  [SCSI] ibmvfc: Reduce unnecessary log noise
  [SCSI] sym53c8xx: free luntbl in sym_hcb_free
  [SCSI] scsi_scan.c: Release mutex in error handling code
  [SCSI] scsi_eh_prep_cmnd should save scmd->underflow
  [SCSI] sd: Support for SCSI disk (SBC) Data Integrity Field
  ...
Linus Torvalds 17 years ago
parent
commit
211c8d4942
91 changed files with 3945 additions and 1028 deletions
  1. 13 0
      drivers/md/dm-mpath.c
  2. 12 12
      drivers/message/fusion/mptbase.c
  3. 2 2
      drivers/message/fusion/mptctl.c
  4. 4 4
      drivers/message/fusion/mptfc.c
  5. 13 13
      drivers/message/fusion/mptlan.c
  6. 27 27
      drivers/message/fusion/mptsas.c
  7. 2 2
      drivers/message/fusion/mptscsih.c
  8. 30 10
      drivers/scsi/3w-9xxx.c
  9. 5 4
      drivers/scsi/3w-9xxx.h
  10. 1 0
      drivers/scsi/Kconfig
  11. 2 0
      drivers/scsi/Makefile
  12. 1 1
      drivers/scsi/advansys.c
  13. 6 6
      drivers/scsi/aha152x.c
  14. 2 2
      drivers/scsi/aic94xx/aic94xx.h
  15. 1 1
      drivers/scsi/aic94xx/aic94xx_hwi.c
  16. 23 23
      drivers/scsi/aic94xx/aic94xx_scb.c
  17. 1 1
      drivers/scsi/aic94xx/aic94xx_task.c
  18. 9 9
      drivers/scsi/aic94xx/aic94xx_tmf.c
  19. 2 2
      drivers/scsi/arm/fas216.c
  20. 1 0
      drivers/scsi/ch.c
  21. 8 0
      drivers/scsi/device_handler/Kconfig
  22. 1 0
      drivers/scsi/device_handler/Makefile
  23. 415 31
      drivers/scsi/device_handler/scsi_dh.c
  24. 802 0
      drivers/scsi/device_handler/scsi_dh_alua.c
  25. 409 235
      drivers/scsi/device_handler/scsi_dh_emc.c
  26. 261 87
      drivers/scsi/device_handler/scsi_dh_hp_sw.c
  27. 132 130
      drivers/scsi/device_handler/scsi_dh_rdac.c
  28. 177 27
      drivers/scsi/ibmvscsi/ibmvfc.c
  29. 40 4
      drivers/scsi/ibmvscsi/ibmvfc.h
  30. 1 1
      drivers/scsi/ibmvscsi/ibmvstgt.c
  31. 1 1
      drivers/scsi/imm.c
  32. 3 3
      drivers/scsi/ipr.h
  33. 8 8
      drivers/scsi/libsas/sas_ata.c
  34. 6 6
      drivers/scsi/libsas/sas_expander.c
  35. 2 2
      drivers/scsi/libsas/sas_port.c
  36. 15 15
      drivers/scsi/libsas/sas_scsi_host.c
  37. 1 1
      drivers/scsi/libsrp.c
  38. 2 2
      drivers/scsi/lpfc/lpfc_init.c
  39. 1 1
      drivers/scsi/lpfc/lpfc_scsi.c
  40. 3 3
      drivers/scsi/lpfc/lpfc_sli.c
  41. 1 1
      drivers/scsi/megaraid/mega_common.h
  42. 8 8
      drivers/scsi/megaraid/megaraid_mbox.c
  43. 2 2
      drivers/scsi/megaraid/megaraid_mm.c
  44. 2 2
      drivers/scsi/nsp32.c
  45. 1 1
      drivers/scsi/nsp32_debug.c
  46. 2 2
      drivers/scsi/pcmcia/nsp_cs.c
  47. 1 1
      drivers/scsi/pcmcia/nsp_debug.c
  48. 1 1
      drivers/scsi/ppa.c
  49. 6 6
      drivers/scsi/qla1280.c
  50. 61 57
      drivers/scsi/qla2xxx/qla_attr.c
  51. 1 1
      drivers/scsi/qla2xxx/qla_dbg.c
  52. 8 4
      drivers/scsi/qla2xxx/qla_def.h
  53. 4 1
      drivers/scsi/qla2xxx/qla_gbl.h
  54. 6 0
      drivers/scsi/qla2xxx/qla_gs.c
  55. 73 60
      drivers/scsi/qla2xxx/qla_init.c
  56. 8 6
      drivers/scsi/qla2xxx/qla_iocb.c
  57. 0 4
      drivers/scsi/qla2xxx/qla_isr.c
  58. 6 3
      drivers/scsi/qla2xxx/qla_mbx.c
  59. 6 10
      drivers/scsi/qla2xxx/qla_mid.c
  60. 59 35
      drivers/scsi/qla2xxx/qla_os.c
  61. 45 3
      drivers/scsi/qla2xxx/qla_sup.c
  62. 1 1
      drivers/scsi/qla2xxx/qla_version.h
  63. 3 1
      drivers/scsi/qla4xxx/ql4_os.c
  64. 48 7
      drivers/scsi/scsi.c
  65. 6 6
      drivers/scsi/scsi_debug.c
  66. 3 3
      drivers/scsi/scsi_devinfo.c
  67. 21 13
      drivers/scsi/scsi_error.c
  68. 49 6
      drivers/scsi/scsi_lib.c
  69. 4 4
      drivers/scsi/scsi_netlink.c
  70. 1 0
      drivers/scsi/scsi_priv.h
  71. 2 2
      drivers/scsi/scsi_proc.c
  72. 7 6
      drivers/scsi/scsi_scan.c
  73. 4 0
      drivers/scsi/scsi_sysfs.c
  74. 1 1
      drivers/scsi/scsi_tgt_priv.h
  75. 6 6
      drivers/scsi/scsi_transport_fc.c
  76. 2 2
      drivers/scsi/scsi_transport_sas.c
  77. 228 63
      drivers/scsi/sd.c
  78. 54 0
      drivers/scsi/sd.h
  79. 538 0
      drivers/scsi/sd_dif.c
  80. 4 7
      drivers/scsi/st.c
  81. 1 1
      drivers/scsi/stex.c
  82. 2 0
      drivers/scsi/sym53c8xx_2/sym_hipd.c
  83. 4 4
      drivers/scsi/tmscsim.c
  84. 4 4
      drivers/scsi/wd7000.c
  85. 4 4
      drivers/scsi/zalon.c
  86. 3 0
      include/scsi/scsi.h
  87. 86 0
      include/scsi/scsi_cmnd.h
  88. 15 2
      include/scsi/scsi_device.h
  89. 11 0
      include/scsi/scsi_dh.h
  90. 2 0
      include/scsi/scsi_eh.h
  91. 85 1
      include/scsi/scsi_host.h

+ 13 - 0
drivers/md/dm-mpath.c

@@ -147,9 +147,12 @@ static struct priority_group *alloc_priority_group(void)
 static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
 static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
 {
 {
 	struct pgpath *pgpath, *tmp;
 	struct pgpath *pgpath, *tmp;
+	struct multipath *m = ti->private;
 
 
 	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
 	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
 		list_del(&pgpath->list);
 		list_del(&pgpath->list);
+		if (m->hw_handler_name)
+			scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
 		dm_put_device(ti, pgpath->path.dev);
 		dm_put_device(ti, pgpath->path.dev);
 		free_pgpath(pgpath);
 		free_pgpath(pgpath);
 	}
 	}
@@ -548,6 +551,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
 {
 {
 	int r;
 	int r;
 	struct pgpath *p;
 	struct pgpath *p;
+	struct multipath *m = ti->private;
 
 
 	/* we need at least a path arg */
 	/* we need at least a path arg */
 	if (as->argc < 1) {
 	if (as->argc < 1) {
@@ -566,6 +570,15 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
 		goto bad;
 		goto bad;
 	}
 	}
 
 
+	if (m->hw_handler_name) {
+		r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev),
+				   m->hw_handler_name);
+		if (r < 0) {
+			dm_put_device(ti, p->path.dev);
+			goto bad;
+		}
+	}
+
 	r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
 	r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
 	if (r) {
 	if (r) {
 		dm_put_device(ti, p->path.dev);
 		dm_put_device(ti, p->path.dev);

+ 12 - 12
drivers/message/fusion/mptbase.c

@@ -273,12 +273,12 @@ mpt_fault_reset_work(struct work_struct *work)
 	ioc_raw_state = mpt_GetIocState(ioc, 0);
 	ioc_raw_state = mpt_GetIocState(ioc, 0);
 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
 		printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
 		printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
-		    ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+		       ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
 		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
 		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
-		    ioc->name, __FUNCTION__);
+		       ioc->name, __func__);
 		rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
 		rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
 		printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
 		printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
-		    __FUNCTION__, (rc == 0) ? "success" : "failed");
+		       __func__, (rc == 0) ? "success" : "failed");
 		ioc_raw_state = mpt_GetIocState(ioc, 0);
 		ioc_raw_state = mpt_GetIocState(ioc, 0);
 		if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
 		if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
 			printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
 			printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
@@ -356,7 +356,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 		MptCallbacks[cb_idx] == NULL) {
 		MptCallbacks[cb_idx] == NULL) {
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
-				__FUNCTION__, ioc->name, cb_idx);
+				__func__, ioc->name, cb_idx);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -420,7 +420,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 		MptCallbacks[cb_idx] == NULL) {
 		MptCallbacks[cb_idx] == NULL) {
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
-				__FUNCTION__, ioc->name, cb_idx);
+				__func__, ioc->name, cb_idx);
 		freeme = 0;
 		freeme = 0;
 		goto out;
 		goto out;
 	}
 	}
@@ -2434,7 +2434,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
 
 
 	if (ioc->cached_fw != NULL) {
 	if (ioc->cached_fw != NULL) {
 		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
 		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
-		    "adapter\n", __FUNCTION__, ioc->name));
+		    "adapter\n", __func__, ioc->name));
 		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
 		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
 		    ioc->cached_fw, CAN_SLEEP)) < 0) {
 		    ioc->cached_fw, CAN_SLEEP)) < 0) {
 			printk(MYIOC_s_WARN_FMT
 			printk(MYIOC_s_WARN_FMT
@@ -3693,7 +3693,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 
 
 	if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
 	if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
 		drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
 		drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
-			"address=%p\n",  ioc->name, __FUNCTION__,
+			"address=%p\n",  ioc->name, __func__,
 			&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
 			&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
 		CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
 		CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
 		if (sleepFlag == CAN_SLEEP)
 		if (sleepFlag == CAN_SLEEP)
@@ -4742,12 +4742,12 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
 		break;
 		break;
 	}
 	}
 
 
-	printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
+	printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
 
 
 	/* Get a MF for this command.
 	/* Get a MF for this command.
 	 */
 	 */
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-		printk("%s: no msg frames!\n",__FUNCTION__);
+		printk("%s: no msg frames!\n",__func__);
 		return -1;
 		return -1;
         }
         }
 
 
@@ -4771,13 +4771,13 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
 	    (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
 	    (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
 	if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
 	if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
 		printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
 		printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-		    __FUNCTION__,
+		    __func__,
 		    sasIoUnitCntrReply->IOCStatus,
 		    sasIoUnitCntrReply->IOCStatus,
 		    sasIoUnitCntrReply->IOCLogInfo);
 		    sasIoUnitCntrReply->IOCLogInfo);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	printk("%s: success\n",__FUNCTION__);
+	printk("%s: success\n",__func__);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5784,7 +5784,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
 
 
 	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
 	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-		    ioc->name,__FUNCTION__));
+		    ioc->name,__func__));
 		return -1;
 		return -1;
 	}
 	}
 
 

+ 2 - 2
drivers/message/fusion/mptctl.c

@@ -505,7 +505,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 	event = le32_to_cpu(pEvReply->Event) & 0xFF;
 	event = le32_to_cpu(pEvReply->Event) & 0xFF;
 
 
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
-	    ioc->name, __FUNCTION__));
+	    ioc->name, __func__));
 	if(async_queue == NULL)
 	if(async_queue == NULL)
 		return 1;
 		return 1;
 
 
@@ -2482,7 +2482,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
 	 */
 	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-		    ioc->name,__FUNCTION__));
+		    ioc->name,__func__));
 		goto out;
 		goto out;
 	}
 	}
 
 

+ 4 - 4
drivers/message/fusion/mptfc.c

@@ -231,28 +231,28 @@ static int
 mptfc_abort(struct scsi_cmnd *SCpnt)
 mptfc_abort(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__);
 }
 }
 
 
 static int
 static int
 mptfc_dev_reset(struct scsi_cmnd *SCpnt)
 mptfc_dev_reset(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__);
 }
 }
 
 
 static int
 static int
 mptfc_bus_reset(struct scsi_cmnd *SCpnt)
 mptfc_bus_reset(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__);
 }
 }
 
 
 static int
 static int
 mptfc_host_reset(struct scsi_cmnd *SCpnt)
 mptfc_host_reset(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__);
 }
 }
 
 
 static void
 static void

+ 13 - 13
drivers/message/fusion/mptlan.c

@@ -610,7 +610,7 @@ mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
 
 
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 			IOC_AND_NETDEV_NAMES_s_s(dev),
 			IOC_AND_NETDEV_NAMES_s_s(dev),
-			__FUNCTION__, sent));
+			__func__, sent));
 
 
 	priv->SendCtl[ctx].skb = NULL;
 	priv->SendCtl[ctx].skb = NULL;
 	pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
 	pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
@@ -676,7 +676,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
 
 
 		dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 		dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 				IOC_AND_NETDEV_NAMES_s_s(dev),
 				IOC_AND_NETDEV_NAMES_s_s(dev),
-				__FUNCTION__, sent));
+				__func__, sent));
 
 
 		priv->SendCtl[ctx].skb = NULL;
 		priv->SendCtl[ctx].skb = NULL;
 		pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
 		pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
@@ -715,7 +715,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 	u16 cur_naa = 0x1000;
 	u16 cur_naa = 0x1000;
 
 
 	dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
 	dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
-			__FUNCTION__, skb));
+			__func__, skb));
 
 
 	spin_lock_irqsave(&priv->txfidx_lock, flags);
 	spin_lock_irqsave(&priv->txfidx_lock, flags);
 	if (priv->mpt_txfidx_tail < 0) {
 	if (priv->mpt_txfidx_tail < 0) {
@@ -723,7 +723,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 
 
 		printk (KERN_ERR "%s: no tx context available: %u\n",
 		printk (KERN_ERR "%s: no tx context available: %u\n",
-			__FUNCTION__, priv->mpt_txfidx_tail);
+			__func__, priv->mpt_txfidx_tail);
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -733,7 +733,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 
 
 		printk (KERN_ERR "%s: Unable to alloc request frame\n",
 		printk (KERN_ERR "%s: Unable to alloc request frame\n",
-			__FUNCTION__);
+			__func__);
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -1208,7 +1208,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 
 
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
 			IOC_AND_NETDEV_NAMES_s_s(dev),
 			IOC_AND_NETDEV_NAMES_s_s(dev),
-			__FUNCTION__, buckets, curr));
+			__func__, buckets, curr));
 
 
 	max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
 	max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
 			(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
 			(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
@@ -1217,9 +1217,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 		mf = mpt_get_msg_frame(LanCtx, mpt_dev);
 		mf = mpt_get_msg_frame(LanCtx, mpt_dev);
 		if (mf == NULL) {
 		if (mf == NULL) {
 			printk (KERN_ERR "%s: Unable to alloc request frame\n",
 			printk (KERN_ERR "%s: Unable to alloc request frame\n",
-				__FUNCTION__);
+				__func__);
 			dioprintk((KERN_ERR "%s: %u buckets remaining\n",
 			dioprintk((KERN_ERR "%s: %u buckets remaining\n",
-				 __FUNCTION__, buckets));
+				 __func__, buckets));
 			goto out;
 			goto out;
 		}
 		}
 		pRecvReq = (LANReceivePostRequest_t *) mf;
 		pRecvReq = (LANReceivePostRequest_t *) mf;
@@ -1244,7 +1244,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 			spin_lock_irqsave(&priv->rxfidx_lock, flags);
 			spin_lock_irqsave(&priv->rxfidx_lock, flags);
 			if (priv->mpt_rxfidx_tail < 0) {
 			if (priv->mpt_rxfidx_tail < 0) {
 				printk (KERN_ERR "%s: Can't alloc context\n",
 				printk (KERN_ERR "%s: Can't alloc context\n",
-					__FUNCTION__);
+					__func__);
 				spin_unlock_irqrestore(&priv->rxfidx_lock,
 				spin_unlock_irqrestore(&priv->rxfidx_lock,
 						       flags);
 						       flags);
 				break;
 				break;
@@ -1267,7 +1267,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 				if (skb == NULL) {
 				if (skb == NULL) {
 					printk (KERN_WARNING
 					printk (KERN_WARNING
 						MYNAM "/%s: Can't alloc skb\n",
 						MYNAM "/%s: Can't alloc skb\n",
-						__FUNCTION__);
+						__func__);
 					priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
 					priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
 					spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
 					spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
 					break;
 					break;
@@ -1305,7 +1305,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 
 
 		if (pSimple == NULL) {
 		if (pSimple == NULL) {
 /**/			printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
 /**/			printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
-/**/				__FUNCTION__);
+/**/				__func__);
 			mpt_free_msg_frame(mpt_dev, mf);
 			mpt_free_msg_frame(mpt_dev, mf);
 			goto out;
 			goto out;
 		}
 		}
@@ -1329,9 +1329,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 
 
 out:
 out:
 	dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
 	dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
-		  __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+		  __func__, buckets, atomic_read(&priv->buckets_out)));
 	dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
 	dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
-	__FUNCTION__, priv->total_posted, priv->total_received));
+	__func__, priv->total_posted, priv->total_received));
 
 
 	clear_bit(0, &priv->post_buckets_active);
 	clear_bit(0, &priv->post_buckets_active);
 }
 }

+ 27 - 27
drivers/message/fusion/mptsas.c

@@ -300,7 +300,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
 	phy_info = port_info->phy_info;
 	phy_info = port_info->phy_info;
 
 
 	dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
 	dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
-	    "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
+	    "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
 	    port_details->num_phys, (unsigned long long)
 	    port_details->num_phys, (unsigned long long)
 	    port_details->phy_bitmask));
 	    port_details->phy_bitmask));
 
 
@@ -411,7 +411,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 		 */
 		 */
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		    "%s: [%p]: deleting phy = %d\n",
 		    "%s: [%p]: deleting phy = %d\n",
-		    ioc->name, __FUNCTION__, port_details, i));
+		    ioc->name, __func__, port_details, i));
 		port_details->num_phys--;
 		port_details->num_phys--;
 		port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
 		port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
 		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
 		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
@@ -497,7 +497,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 			continue;
 			continue;
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		    "%s: [%p]: phy_id=%02d num_phys=%02d "
 		    "%s: [%p]: phy_id=%02d num_phys=%02d "
-		    "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
+		    "bitmask=0x%016llX\n", ioc->name, __func__,
 		    port_details, i, port_details->num_phys,
 		    port_details, i, port_details->num_phys,
 		    (unsigned long long)port_details->phy_bitmask));
 		    (unsigned long long)port_details->phy_bitmask));
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
@@ -553,7 +553,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
 
 
 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
-		    ioc->name,__FUNCTION__, __LINE__));
+		    ioc->name,__func__, __LINE__));
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -606,7 +606,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
 	    GFP_ATOMIC);
 	    GFP_ATOMIC);
 	if (!target_reset_list) {
 	if (!target_reset_list) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-		    ioc->name,__FUNCTION__, __LINE__));
+		    ioc->name,__func__, __LINE__));
 		return;
 		return;
 	}
 	}
 
 
@@ -673,7 +673,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
 	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
 	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
 	if (!ev) {
 	if (!ev) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-		    ioc->name,__FUNCTION__, __LINE__));
+		    ioc->name,__func__, __LINE__));
 		return;
 		return;
 	}
 	}
 
 
@@ -1183,7 +1183,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
 	reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
 	reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
 	if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
 	if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
 		printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
 		printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-		    ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
+		    ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
 		error = -ENXIO;
 		error = -ENXIO;
 		goto out_unlock;
 		goto out_unlock;
 	}
 	}
@@ -1270,14 +1270,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
 
 	if (!rsp) {
 	if (!rsp) {
 		printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
 		printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
-		    ioc->name, __FUNCTION__);
+		    ioc->name, __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	/* do we need to support multiple segments? */
 	/* do we need to support multiple segments? */
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 		printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
 		printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
-		    ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+		    ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
 		    rsp->bio->bi_vcnt, rsp->data_len);
 		    rsp->bio->bi_vcnt, rsp->data_len);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -1343,7 +1343,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
 
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
 	if (!timeleft) {
 	if (!timeleft) {
-		printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
+		printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
 		/* On timeout reset the board */
 		/* On timeout reset the board */
 		mpt_HardResetHandler(ioc, CAN_SLEEP);
 		mpt_HardResetHandler(ioc, CAN_SLEEP);
 		ret = -ETIMEDOUT;
 		ret = -ETIMEDOUT;
@@ -1361,7 +1361,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 		rsp->data_len -= smprep->ResponseDataLength;
 		rsp->data_len -= smprep->ResponseDataLength;
 	} else {
 	} else {
 		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
 		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
-		    ioc->name, __FUNCTION__);
+		    ioc->name, __func__);
 		ret = -ENXIO;
 		ret = -ENXIO;
 	}
 	}
 unmap:
 unmap:
@@ -2006,7 +2006,7 @@ static int mptsas_probe_one_phy(struct device *dev,
 			if (error) {
 			if (error) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 				goto out;
 				goto out;
 			}
 			}
 			mptsas_set_port(ioc, phy_info, port);
 			mptsas_set_port(ioc, phy_info, port);
@@ -2076,7 +2076,7 @@ static int mptsas_probe_one_phy(struct device *dev,
 		if (!rphy) {
 		if (!rphy) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-				__FUNCTION__, __LINE__));
+				__func__, __LINE__));
 			goto out;
 			goto out;
 		}
 		}
 
 
@@ -2085,7 +2085,7 @@ static int mptsas_probe_one_phy(struct device *dev,
 		if (error) {
 		if (error) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-				__FUNCTION__, __LINE__));
+				__func__, __LINE__));
 			sas_rphy_free(rphy);
 			sas_rphy_free(rphy);
 			goto out;
 			goto out;
 		}
 		}
@@ -2613,7 +2613,7 @@ mptsas_hotplug_work(struct work_struct *work)
 				    (ev->channel << 8) + ev->id)) {
 				    (ev->channel << 8) + ev->id)) {
 					dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-						__FUNCTION__, __LINE__));
+						__func__, __LINE__));
 					break;
 					break;
 				}
 				}
 				phy_info = mptsas_find_phyinfo_by_sas_address(
 				phy_info = mptsas_find_phyinfo_by_sas_address(
@@ -2633,20 +2633,20 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!phy_info){
 		if (!phy_info){
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-				__FUNCTION__, __LINE__));
+				__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 		if (!phy_info->port_details) {
 		if (!phy_info->port_details) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 		rphy = mptsas_get_rphy(phy_info);
 		rphy = mptsas_get_rphy(phy_info);
 		if (!rphy) {
 		if (!rphy) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2654,7 +2654,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!port) {
 		if (!port) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2665,7 +2665,7 @@ mptsas_hotplug_work(struct work_struct *work)
 			if (!vtarget) {
 			if (!vtarget) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 				break;
 				break;
 			}
 			}
 
 
@@ -2720,7 +2720,7 @@ mptsas_hotplug_work(struct work_struct *work)
 			(ev->channel << 8) + ev->id)) {
 			(ev->channel << 8) + ev->id)) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2732,7 +2732,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!phy_info || !phy_info->port_details) {
 		if (!phy_info || !phy_info->port_details) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2744,7 +2744,7 @@ mptsas_hotplug_work(struct work_struct *work)
 			if (!vtarget) {
 			if (!vtarget) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				    "%s: exit at line=%d\n", ioc->name,
 				    "%s: exit at line=%d\n", ioc->name,
-				    __FUNCTION__, __LINE__));
+				    __func__, __LINE__));
 				break;
 				break;
 			}
 			}
 			/*
 			/*
@@ -2767,7 +2767,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (mptsas_get_rphy(phy_info)) {
 		if (mptsas_get_rphy(phy_info)) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			if (ev->channel) printk("%d\n", __LINE__);
 			if (ev->channel) printk("%d\n", __LINE__);
 			break;
 			break;
 		}
 		}
@@ -2776,7 +2776,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!port) {
 		if (!port) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 		memcpy(&phy_info->attached, &sas_device,
 		memcpy(&phy_info->attached, &sas_device,
@@ -2801,7 +2801,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!rphy) {
 		if (!rphy) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break; /* non-fatal: an rphy can be added later */
 			break; /* non-fatal: an rphy can be added later */
 		}
 		}
 
 
@@ -2809,7 +2809,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (sas_rphy_add(rphy)) {
 		if (sas_rphy_add(rphy)) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			sas_rphy_free(rphy);
 			sas_rphy_free(rphy);
 			break;
 			break;
 		}
 		}

+ 2 - 2
drivers/message/fusion/mptscsih.c

@@ -461,7 +461,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
 
 
 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
-		    ioc->name,__FUNCTION__));
+		    ioc->name,__func__));
 		return;
 		return;
 	}
 	}
 
 
@@ -2187,7 +2187,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
 				(ioc->debug_level & MPT_DEBUG_TM ))
 				(ioc->debug_level & MPT_DEBUG_TM ))
 		printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
 		printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
 			"iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
 			"iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
-			"term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
+			"term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
 			 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
 			 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
 			le16_to_cpu(pScsiTmReply->IOCStatus),
 			le16_to_cpu(pScsiTmReply->IOCStatus),
 			le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
 			le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,

+ 30 - 10
drivers/scsi/3w-9xxx.c

@@ -4,7 +4,7 @@
    Written By: Adam Radford <linuxraid@amcc.com>
    Written By: Adam Radford <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
 
 
-   Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
@@ -71,6 +71,10 @@
                  Add support for 9650SE controllers.
                  Add support for 9650SE controllers.
    2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
    2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
    2.26.02.010 - Add support for 9690SA controllers.
    2.26.02.010 - Add support for 9690SA controllers.
+   2.26.02.011 - Increase max AENs drained to 256.
+                 Add MSI support and "use_msi" module parameter.
+                 Fix bug in twa_get_param() on 4GB+.
+                 Use pci_resource_len() for ioremap().
 */
 */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -95,7 +99,7 @@
 #include "3w-9xxx.h"
 #include "3w-9xxx.h"
 
 
 /* Globals */
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.010"
+#define TW_DRIVER_VERSION "2.26.02.011"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
 static int twa_major = -1;
@@ -107,6 +111,10 @@ MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(TW_DRIVER_VERSION);
 MODULE_VERSION(TW_DRIVER_VERSION);
 
 
+static int use_msi = 0;
+module_param(use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts.  Default: 0");
+
 /* Function prototypes */
 /* Function prototypes */
 static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
 static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
 static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
 static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
@@ -1038,7 +1046,6 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl
 	TW_Command_Full *full_command_packet;
 	TW_Command_Full *full_command_packet;
 	TW_Command *command_packet;
 	TW_Command *command_packet;
 	TW_Param_Apache *param;
 	TW_Param_Apache *param;
-	unsigned long param_value;
 	void *retval = NULL;
 	void *retval = NULL;
 
 
 	/* Setup the command packet */
 	/* Setup the command packet */
@@ -1057,9 +1064,8 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl
 	param->table_id = cpu_to_le16(table_id | 0x8000);
 	param->table_id = cpu_to_le16(table_id | 0x8000);
 	param->parameter_id = cpu_to_le16(parameter_id);
 	param->parameter_id = cpu_to_le16(parameter_id);
 	param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
 	param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
-	param_value = tw_dev->generic_buffer_phys[request_id];
 
 
-	command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(param_value);
+	command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
 	command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
 	command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
 
 
 	/* Post the command packet to the board */
 	/* Post the command packet to the board */
@@ -2000,7 +2006,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 {
 {
 	struct Scsi_Host *host = NULL;
 	struct Scsi_Host *host = NULL;
 	TW_Device_Extension *tw_dev;
 	TW_Device_Extension *tw_dev;
-	u32 mem_addr;
+	unsigned long mem_addr, mem_len;
 	int retval = -ENODEV;
 	int retval = -ENODEV;
 
 
 	retval = pci_enable_device(pdev);
 	retval = pci_enable_device(pdev);
@@ -2045,13 +2051,16 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 		goto out_free_device_extension;
 		goto out_free_device_extension;
 	}
 	}
 
 
-	if (pdev->device == PCI_DEVICE_ID_3WARE_9000)
+	if (pdev->device == PCI_DEVICE_ID_3WARE_9000) {
 		mem_addr = pci_resource_start(pdev, 1);
 		mem_addr = pci_resource_start(pdev, 1);
-	else
+		mem_len = pci_resource_len(pdev, 1);
+	} else {
 		mem_addr = pci_resource_start(pdev, 2);
 		mem_addr = pci_resource_start(pdev, 2);
+		mem_len = pci_resource_len(pdev, 2);
+	}
 
 
 	/* Save base address */
 	/* Save base address */
-	tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
+	tw_dev->base_addr = ioremap(mem_addr, mem_len);
 	if (!tw_dev->base_addr) {
 	if (!tw_dev->base_addr) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
 		goto out_release_mem_region;
 		goto out_release_mem_region;
@@ -2086,7 +2095,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 
 
 	pci_set_drvdata(pdev, host);
 	pci_set_drvdata(pdev, host);
 
 
-	printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n",
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%lx, IRQ: %d.\n",
 	       host->host_no, mem_addr, pdev->irq);
 	       host->host_no, mem_addr, pdev->irq);
 	printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
 	printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
 	       host->host_no,
 	       host->host_no,
@@ -2097,6 +2106,11 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 	       le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
 	       le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
 				     TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
 				     TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
 
 
+	/* Try to enable MSI */
+	if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) &&
+	    !pci_enable_msi(pdev))
+		set_bit(TW_USING_MSI, &tw_dev->flags);
+
 	/* Now setup the interrupt handler */
 	/* Now setup the interrupt handler */
 	retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
 	retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
 	if (retval) {
 	if (retval) {
@@ -2120,6 +2134,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 	return 0;
 	return 0;
 
 
 out_remove_host:
 out_remove_host:
+	if (test_bit(TW_USING_MSI, &tw_dev->flags))
+		pci_disable_msi(pdev);
 	scsi_remove_host(host);
 	scsi_remove_host(host);
 out_iounmap:
 out_iounmap:
 	iounmap(tw_dev->base_addr);
 	iounmap(tw_dev->base_addr);
@@ -2151,6 +2167,10 @@ static void twa_remove(struct pci_dev *pdev)
 	/* Shutdown the card */
 	/* Shutdown the card */
 	__twa_shutdown(tw_dev);
 	__twa_shutdown(tw_dev);
 
 
+	/* Disable MSI if enabled */
+	if (test_bit(TW_USING_MSI, &tw_dev->flags))
+		pci_disable_msi(pdev);
+
 	/* Free IO remapping */
 	/* Free IO remapping */
 	iounmap(tw_dev->base_addr);
 	iounmap(tw_dev->base_addr);
 
 

+ 5 - 4
drivers/scsi/3w-9xxx.h

@@ -4,7 +4,7 @@
    Written By: Adam Radford <linuxraid@amcc.com>
    Written By: Adam Radford <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
 
 
-   Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
@@ -319,8 +319,8 @@ static twa_message_type twa_error_table[] = {
 
 
 /* Compatibility defines */
 /* Compatibility defines */
 #define TW_9000_ARCH_ID 0x5
 #define TW_9000_ARCH_ID 0x5
-#define TW_CURRENT_DRIVER_SRL 30
-#define TW_CURRENT_DRIVER_BUILD 80
+#define TW_CURRENT_DRIVER_SRL 35
+#define TW_CURRENT_DRIVER_BUILD 0
 #define TW_CURRENT_DRIVER_BRANCH 0
 #define TW_CURRENT_DRIVER_BRANCH 0
 
 
 /* Phase defines */
 /* Phase defines */
@@ -352,8 +352,9 @@ static twa_message_type twa_error_table[] = {
 #define TW_MAX_RESET_TRIES		      2
 #define TW_MAX_RESET_TRIES		      2
 #define TW_MAX_CMDS_PER_LUN		      254
 #define TW_MAX_CMDS_PER_LUN		      254
 #define TW_MAX_RESPONSE_DRAIN		      256
 #define TW_MAX_RESPONSE_DRAIN		      256
-#define TW_MAX_AEN_DRAIN		      40
+#define TW_MAX_AEN_DRAIN		      255
 #define TW_IN_RESET                           2
 #define TW_IN_RESET                           2
+#define TW_USING_MSI			      3
 #define TW_IN_ATTENTION_LOOP		      4
 #define TW_IN_ATTENTION_LOOP		      4
 #define TW_MAX_SECTORS                        256
 #define TW_MAX_SECTORS                        256
 #define TW_AEN_WAIT_TIME                      1000
 #define TW_AEN_WAIT_TIME                      1000

+ 1 - 0
drivers/scsi/Kconfig

@@ -63,6 +63,7 @@ comment "SCSI support type (disk, tape, CD-ROM)"
 config BLK_DEV_SD
 config BLK_DEV_SD
 	tristate "SCSI disk support"
 	tristate "SCSI disk support"
 	depends on SCSI
 	depends on SCSI
+	select CRC_T10DIF
 	---help---
 	---help---
 	  If you want to use SCSI hard disks, Fibre Channel disks,
 	  If you want to use SCSI hard disks, Fibre Channel disks,
 	  Serial ATA (SATA) or Parallel ATA (PATA) hard disks,
 	  Serial ATA (SATA) or Parallel ATA (PATA) hard disks,

+ 2 - 0
drivers/scsi/Makefile

@@ -151,6 +151,8 @@ scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 
 
 sd_mod-objs	:= sd.o
 sd_mod-objs	:= sd.o
+sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o
+
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 		:= -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \
 		:= -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \

+ 1 - 1
drivers/scsi/advansys.c

@@ -2278,7 +2278,7 @@ do { \
 #define ASC_DBG(lvl, format, arg...) {					\
 #define ASC_DBG(lvl, format, arg...) {					\
 	if (asc_dbglvl >= (lvl))					\
 	if (asc_dbglvl >= (lvl))					\
 		printk(KERN_DEBUG "%s: %s: " format, DRV_NAME,		\
 		printk(KERN_DEBUG "%s: %s: " format, DRV_NAME,		\
-			__FUNCTION__ , ## arg);				\
+			__func__ , ## arg);				\
 }
 }
 
 
 #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
 #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \

+ 6 - 6
drivers/scsi/aha152x.c

@@ -288,20 +288,20 @@ static LIST_HEAD(aha152x_host_list);
 #define DO_LOCK(flags)	\
 #define DO_LOCK(flags)	\
 	do { \
 	do { \
 		if(spin_is_locked(&QLOCK)) { \
 		if(spin_is_locked(&QLOCK)) { \
-			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
 		} \
 		} \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
 		spin_lock_irqsave(&QLOCK,flags); \
 		spin_lock_irqsave(&QLOCK,flags); \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
-		QLOCKER=__FUNCTION__; \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
+		QLOCKER=__func__; \
 		QLOCKERL=__LINE__; \
 		QLOCKERL=__LINE__; \
 	} while(0)
 	} while(0)
 
 
 #define DO_UNLOCK(flags)	\
 #define DO_UNLOCK(flags)	\
 	do { \
 	do { \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
 		spin_unlock_irqrestore(&QLOCK,flags); \
 		spin_unlock_irqrestore(&QLOCK,flags); \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
 		QLOCKER="(not locked)"; \
 		QLOCKER="(not locked)"; \
 		QLOCKERL=0; \
 		QLOCKERL=0; \
 	} while(0)
 	} while(0)

+ 2 - 2
drivers/scsi/aic94xx/aic94xx.h

@@ -39,9 +39,9 @@
 
 
 #ifdef ASD_ENTER_EXIT
 #ifdef ASD_ENTER_EXIT
 #define ENTER  printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
 #define ENTER  printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
-		__FUNCTION__)
+		__func__)
 #define EXIT   printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
 #define EXIT   printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
-		__FUNCTION__)
+		__func__)
 #else
 #else
 #define ENTER
 #define ENTER
 #define EXIT
 #define EXIT

+ 1 - 1
drivers/scsi/aic94xx/aic94xx_hwi.c

@@ -1359,7 +1359,7 @@ int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
 	struct asd_ascb *ascb_list;
 	struct asd_ascb *ascb_list;
 
 
 	if (!phy_mask) {
 	if (!phy_mask) {
-		asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
+		asd_printk("%s called with phy_mask of 0!?\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 23 - 23
drivers/scsi/aic94xx/aic94xx_scb.c

@@ -211,7 +211,7 @@ static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
 		phy->asd_port = port;
 		phy->asd_port = port;
 	}
 	}
 	ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
 	ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
-		    __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id);
+		    __func__, phy->asd_port->phy_mask, sas_phy->id);
 	asd_update_port_links(asd_ha, phy);
 	asd_update_port_links(asd_ha, phy);
 	spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
 	spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
 }
 }
@@ -294,7 +294,7 @@ static void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
 		struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
 		struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
 							  GFP_ATOMIC);
 							  GFP_ATOMIC);
 		if (!cp) {
 		if (!cp) {
-			asd_printk("%s: out of memory\n", __FUNCTION__);
+			asd_printk("%s: out of memory\n", __func__);
 			goto out;
 			goto out;
 		}
 		}
 		ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
 		ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
@@ -446,7 +446,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		struct domain_device *failed_dev = NULL;
 		struct domain_device *failed_dev = NULL;
 
 
 		ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
 		ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
-			    __FUNCTION__, dl->status_block[3]);
+			    __func__, dl->status_block[3]);
 
 
 		/*
 		/*
 		 * Find the task that caused the abort and abort it first.
 		 * Find the task that caused the abort and abort it first.
@@ -474,7 +474,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
 
 		if (!failed_dev) {
 		if (!failed_dev) {
 			ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
 			ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
-				    __FUNCTION__, tc_abort);
+				    __func__, tc_abort);
 			goto out;
 			goto out;
 		}
 		}
 
 
@@ -502,7 +502,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		conn_handle = *((u16*)(&dl->status_block[1]));
 		conn_handle = *((u16*)(&dl->status_block[1]));
 		conn_handle = le16_to_cpu(conn_handle);
 		conn_handle = le16_to_cpu(conn_handle);
 
 
-		ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
+		ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __func__,
 			    dl->status_block[3]);
 			    dl->status_block[3]);
 
 
 		/* Find the last pending task for the device... */
 		/* Find the last pending task for the device... */
@@ -522,7 +522,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
 
 		if (!last_dev_task) {
 		if (!last_dev_task) {
 			ASD_DPRINTK("%s: Device reset for idle device %d?\n",
 			ASD_DPRINTK("%s: Device reset for idle device %d?\n",
-				    __FUNCTION__, conn_handle);
+				    __func__, conn_handle);
 			goto out;
 			goto out;
 		}
 		}
 
 
@@ -549,10 +549,10 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		goto out;
 		goto out;
 	}
 	}
 	case SIGNAL_NCQ_ERROR:
 	case SIGNAL_NCQ_ERROR:
-		ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
+		ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __func__);
 		goto out;
 		goto out;
 	case CLEAR_NCQ_ERROR:
 	case CLEAR_NCQ_ERROR:
-		ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
+		ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __func__);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -560,26 +560,26 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
 
 	switch (sb_opcode) {
 	switch (sb_opcode) {
 	case BYTES_DMAED:
 	case BYTES_DMAED:
-		ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
+		ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id);
 		asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
 		asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
 		break;
 		break;
 	case PRIMITIVE_RECVD:
 	case PRIMITIVE_RECVD:
-		ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__,
 			    phy_id);
 			    phy_id);
 		asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
 		asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
 		break;
 		break;
 	case PHY_EVENT:
 	case PHY_EVENT:
-		ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
+		ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id);
 		asd_phy_event_tasklet(ascb, dl);
 		asd_phy_event_tasklet(ascb, dl);
 		break;
 		break;
 	case LINK_RESET_ERROR:
 	case LINK_RESET_ERROR:
-		ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__,
 			    phy_id);
 			    phy_id);
 		asd_link_reset_err_tasklet(ascb, dl, phy_id);
 		asd_link_reset_err_tasklet(ascb, dl, phy_id);
 		break;
 		break;
 	case TIMER_EVENT:
 	case TIMER_EVENT:
 		ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
 		ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
-			    __FUNCTION__, phy_id);
+			    __func__, phy_id);
 		asd_turn_led(asd_ha, phy_id, 0);
 		asd_turn_led(asd_ha, phy_id, 0);
 		/* the device is gone */
 		/* the device is gone */
 		sas_phy_disconnected(sas_phy);
 		sas_phy_disconnected(sas_phy);
@@ -587,7 +587,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
 		sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
 		break;
 		break;
 	default:
 	default:
-		ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __func__,
 			    phy_id, sb_opcode);
 			    phy_id, sb_opcode);
 		ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
 		ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
 			    edb, dl->opcode);
 			    edb, dl->opcode);
@@ -654,7 +654,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
 
 
 	if (status != 0) {
 	if (status != 0) {
 		ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
 		ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
-			    __FUNCTION__, phy_id, status);
+			    __func__, phy_id, status);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -663,7 +663,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
 		asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
 		asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
 		asd_turn_led(asd_ha, phy_id, 0);
 		asd_turn_led(asd_ha, phy_id, 0);
 		asd_control_led(asd_ha, phy_id, 0);
 		asd_control_led(asd_ha, phy_id, 0);
-		ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
+		ASD_DPRINTK("%s: disable phy%d\n", __func__, phy_id);
 		break;
 		break;
 
 
 	case ENABLE_PHY:
 	case ENABLE_PHY:
@@ -673,40 +673,40 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
 			get_lrate_mode(phy, oob_mode);
 			get_lrate_mode(phy, oob_mode);
 			asd_turn_led(asd_ha, phy_id, 1);
 			asd_turn_led(asd_ha, phy_id, 1);
 			ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
 			ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
-				    __FUNCTION__, phy_id,phy->sas_phy.linkrate,
+				    __func__, phy_id,phy->sas_phy.linkrate,
 				    phy->sas_phy.iproto);
 				    phy->sas_phy.iproto);
 		} else if (oob_status & CURRENT_SPINUP_HOLD) {
 		} else if (oob_status & CURRENT_SPINUP_HOLD) {
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_turn_led(asd_ha, phy_id, 1);
 			asd_turn_led(asd_ha, phy_id, 1);
-			ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
+			ASD_DPRINTK("%s: phy%d, spinup hold\n", __func__,
 				    phy_id);
 				    phy_id);
 		} else if (oob_status & CURRENT_ERR_MASK) {
 		} else if (oob_status & CURRENT_ERR_MASK) {
 			asd_turn_led(asd_ha, phy_id, 0);
 			asd_turn_led(asd_ha, phy_id, 0);
 			ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
 			ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
-				    __FUNCTION__, phy_id, oob_status);
+				    __func__, phy_id, oob_status);
 		} else if (oob_status & (CURRENT_HOT_PLUG_CNCT
 		} else if (oob_status & (CURRENT_HOT_PLUG_CNCT
 					 | CURRENT_DEVICE_PRESENT))  {
 					 | CURRENT_DEVICE_PRESENT))  {
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_turn_led(asd_ha, phy_id, 1);
 			asd_turn_led(asd_ha, phy_id, 1);
 			ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
 			ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
-				    __FUNCTION__, phy_id);
+				    __func__, phy_id);
 		} else {
 		} else {
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_turn_led(asd_ha, phy_id, 0);
 			asd_turn_led(asd_ha, phy_id, 0);
 			ASD_DPRINTK("%s: phy%d: no device present: "
 			ASD_DPRINTK("%s: phy%d: no device present: "
 				    "oob_status:0x%x\n",
 				    "oob_status:0x%x\n",
-				    __FUNCTION__, phy_id, oob_status);
+				    __func__, phy_id, oob_status);
 		}
 		}
 		break;
 		break;
 	case RELEASE_SPINUP_HOLD:
 	case RELEASE_SPINUP_HOLD:
 	case PHY_NO_OP:
 	case PHY_NO_OP:
 	case EXECUTE_HARD_RESET:
 	case EXECUTE_HARD_RESET:
-		ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __func__,
 			    phy_id, control_phy->sub_func);
 			    phy_id, control_phy->sub_func);
 		/* XXX finish */
 		/* XXX finish */
 		break;
 		break;
 	default:
 	default:
-		ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __func__,
 			    phy_id, control_phy->sub_func);
 			    phy_id, control_phy->sub_func);
 		break;
 		break;
 	}
 	}

+ 1 - 1
drivers/scsi/aic94xx/aic94xx_task.c

@@ -320,7 +320,7 @@ Again:
 	case TC_RESUME:
 	case TC_RESUME:
 	case TC_PARTIAL_SG_LIST:
 	case TC_PARTIAL_SG_LIST:
 	default:
 	default:
-		ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);
+		ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __func__, opcode);
 		break;
 		break;
 	}
 	}
 
 

+ 9 - 9
drivers/scsi/aic94xx/aic94xx_tmf.c

@@ -75,12 +75,12 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
 					     struct done_list_struct *dl)
 					     struct done_list_struct *dl)
 {
 {
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
-	ASD_DPRINTK("%s: here\n", __FUNCTION__);
+	ASD_DPRINTK("%s: here\n", __func__);
 	if (!del_timer(&ascb->timer)) {
 	if (!del_timer(&ascb->timer)) {
-		ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
+		ASD_DPRINTK("%s: couldn't delete timer\n", __func__);
 		return;
 		return;
 	}
 	}
-	ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
+	ASD_DPRINTK("%s: opcode: 0x%x\n", __func__, dl->opcode);
 	tcs->dl_opcode = dl->opcode;
 	tcs->dl_opcode = dl->opcode;
 	complete(ascb->completion);
 	complete(ascb->completion);
 	asd_ascb_free(ascb);
 	asd_ascb_free(ascb);
@@ -91,7 +91,7 @@ static void asd_clear_nexus_timedout(unsigned long data)
 	struct asd_ascb *ascb = (void *)data;
 	struct asd_ascb *ascb = (void *)data;
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
 
 
-	ASD_DPRINTK("%s: here\n", __FUNCTION__);
+	ASD_DPRINTK("%s: here\n", __func__);
 	tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
 	tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
 	complete(ascb->completion);
 	complete(ascb->completion);
 }
 }
@@ -103,7 +103,7 @@ static void asd_clear_nexus_timedout(unsigned long data)
 	DECLARE_COMPLETION_ONSTACK(completion); \
 	DECLARE_COMPLETION_ONSTACK(completion); \
 	DECLARE_TCS(tcs); \
 	DECLARE_TCS(tcs); \
 		\
 		\
-	ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
+	ASD_DPRINTK("%s: PRE\n", __func__); \
         res = 1;                \
         res = 1;                \
 	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
 	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
 	if (!ascb)              \
 	if (!ascb)              \
@@ -115,12 +115,12 @@ static void asd_clear_nexus_timedout(unsigned long data)
 	scb->header.opcode = CLEAR_NEXUS
 	scb->header.opcode = CLEAR_NEXUS
 
 
 #define CLEAR_NEXUS_POST        \
 #define CLEAR_NEXUS_POST        \
-	ASD_DPRINTK("%s: POST\n", __FUNCTION__); \
+	ASD_DPRINTK("%s: POST\n", __func__); \
 	res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
 	res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
 				   asd_clear_nexus_timedout);              \
 				   asd_clear_nexus_timedout);              \
 	if (res)                \
 	if (res)                \
 		goto out_err;   \
 		goto out_err;   \
-	ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
+	ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __func__); \
 	wait_for_completion(&completion); \
 	wait_for_completion(&completion); \
 	res = tcs.dl_opcode; \
 	res = tcs.dl_opcode; \
 	if (res == TC_NO_ERROR) \
 	if (res == TC_NO_ERROR) \
@@ -417,7 +417,7 @@ int asd_abort_task(struct sas_task *task)
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		res = TMF_RESP_FUNC_COMPLETE;
 		res = TMF_RESP_FUNC_COMPLETE;
-		ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+		ASD_DPRINTK("%s: task 0x%p done\n", __func__, task);
 		goto out_done;
 		goto out_done;
 	}
 	}
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -481,7 +481,7 @@ int asd_abort_task(struct sas_task *task)
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		res = TMF_RESP_FUNC_COMPLETE;
 		res = TMF_RESP_FUNC_COMPLETE;
-		ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+		ASD_DPRINTK("%s: task 0x%p done\n", __func__, task);
 		goto out_done;
 		goto out_done;
 	}
 	}
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 	spin_unlock_irqrestore(&task->task_state_lock, flags);

+ 2 - 2
drivers/scsi/arm/fas216.c

@@ -240,7 +240,7 @@ static void __fas216_checkmagic(FAS216_Info *info, const char *func)
 		panic("scsi memory space corrupted in %s", func);
 		panic("scsi memory space corrupted in %s", func);
 	}
 	}
 }
 }
-#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
+#define fas216_checkmagic(info) __fas216_checkmagic((info), __func__)
 #else
 #else
 #define fas216_checkmagic(info)
 #define fas216_checkmagic(info)
 #endif
 #endif
@@ -2658,7 +2658,7 @@ int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
 	fas216_checkmagic(info);
 	fas216_checkmagic(info);
 
 
 	printk("scsi%d.%c: %s: resetting host\n",
 	printk("scsi%d.%c: %s: resetting host\n",
-		info->host->host_no, '0' + SCpnt->device->id, __FUNCTION__);
+		info->host->host_no, '0' + SCpnt->device->id, __func__);
 
 
 	/*
 	/*
 	 * Reset the SCSI chip.
 	 * Reset the SCSI chip.

+ 1 - 0
drivers/scsi/ch.c

@@ -930,6 +930,7 @@ static int ch_probe(struct device *dev)
 	if (init)
 	if (init)
 		ch_init_elem(ch);
 		ch_init_elem(ch);
 
 
+	dev_set_drvdata(dev, ch);
 	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
 	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
 
 
 	return 0;
 	return 0;

+ 8 - 0
drivers/scsi/device_handler/Kconfig

@@ -30,3 +30,11 @@ config SCSI_DH_EMC
 	depends on SCSI_DH
 	depends on SCSI_DH
 	help
 	help
 	If you have a EMC CLARiiON select y. Otherwise, say N.
 	If you have a EMC CLARiiON select y. Otherwise, say N.
+
+config SCSI_DH_ALUA
+	tristate "SPC-3 ALUA Device Handler (EXPERIMENTAL)"
+	depends on SCSI_DH && EXPERIMENTAL
+	help
+	  SCSI Device handler for generic SPC-3 Asymmetric Logical Unit
+	  Access (ALUA).
+

+ 1 - 0
drivers/scsi/device_handler/Makefile

@@ -5,3 +5,4 @@ obj-$(CONFIG_SCSI_DH)		+= scsi_dh.o
 obj-$(CONFIG_SCSI_DH_RDAC)	+= scsi_dh_rdac.o
 obj-$(CONFIG_SCSI_DH_RDAC)	+= scsi_dh_rdac.o
 obj-$(CONFIG_SCSI_DH_HP_SW)	+= scsi_dh_hp_sw.o
 obj-$(CONFIG_SCSI_DH_HP_SW)	+= scsi_dh_hp_sw.o
 obj-$(CONFIG_SCSI_DH_EMC)	+= scsi_dh_emc.o
 obj-$(CONFIG_SCSI_DH_EMC)	+= scsi_dh_emc.o
+obj-$(CONFIG_SCSI_DH_ALUA)	+= scsi_dh_alua.o

+ 415 - 31
drivers/scsi/device_handler/scsi_dh.c

@@ -24,8 +24,16 @@
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_dh.h>
 #include "../scsi_priv.h"
 #include "../scsi_priv.h"
 
 
+struct scsi_dh_devinfo_list {
+	struct list_head node;
+	char vendor[9];
+	char model[17];
+	struct scsi_device_handler *handler;
+};
+
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(list_lock);
 static LIST_HEAD(scsi_dh_list);
 static LIST_HEAD(scsi_dh_list);
+static LIST_HEAD(scsi_dh_dev_list);
 
 
 static struct scsi_device_handler *get_device_handler(const char *name)
 static struct scsi_device_handler *get_device_handler(const char *name)
 {
 {
@@ -33,7 +41,7 @@ static struct scsi_device_handler *get_device_handler(const char *name)
 
 
 	spin_lock(&list_lock);
 	spin_lock(&list_lock);
 	list_for_each_entry(tmp, &scsi_dh_list, list) {
 	list_for_each_entry(tmp, &scsi_dh_list, list) {
-		if (!strcmp(tmp->name, name)) {
+		if (!strncmp(tmp->name, name, strlen(tmp->name))) {
 			found = tmp;
 			found = tmp;
 			break;
 			break;
 		}
 		}
@@ -42,11 +50,307 @@ static struct scsi_device_handler *get_device_handler(const char *name)
 	return found;
 	return found;
 }
 }
 
 
+
+static struct scsi_device_handler *
+scsi_dh_cache_lookup(struct scsi_device *sdev)
+{
+	struct scsi_dh_devinfo_list *tmp;
+	struct scsi_device_handler *found_dh = NULL;
+
+	spin_lock(&list_lock);
+	list_for_each_entry(tmp, &scsi_dh_dev_list, node) {
+		if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) &&
+		    !strncmp(sdev->model, tmp->model, strlen(tmp->model))) {
+			found_dh = tmp->handler;
+			break;
+		}
+	}
+	spin_unlock(&list_lock);
+
+	return found_dh;
+}
+
+static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh,
+				  struct scsi_device *sdev)
+{
+	int i, found = 0;
+
+	for(i = 0; scsi_dh->devlist[i].vendor; i++) {
+		if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor,
+			     strlen(scsi_dh->devlist[i].vendor)) &&
+		    !strncmp(sdev->model, scsi_dh->devlist[i].model,
+			     strlen(scsi_dh->devlist[i].model))) {
+			found = 1;
+			break;
+		}
+	}
+	return found;
+}
+
+/*
+ * device_handler_match - Attach a device handler to a device
+ * @scsi_dh - The device handler to match against or NULL
+ * @sdev - SCSI device to be tested against @scsi_dh
+ *
+ * Tests @sdev against the device handler @scsi_dh or against
+ * all registered device_handler if @scsi_dh == NULL.
+ * Returns the found device handler or NULL if not found.
+ */
+static struct scsi_device_handler *
+device_handler_match(struct scsi_device_handler *scsi_dh,
+		     struct scsi_device *sdev)
+{
+	struct scsi_device_handler *found_dh = NULL;
+	struct scsi_dh_devinfo_list *tmp;
+
+	found_dh = scsi_dh_cache_lookup(sdev);
+	if (found_dh)
+		return found_dh;
+
+	if (scsi_dh) {
+		if (scsi_dh_handler_lookup(scsi_dh, sdev))
+			found_dh = scsi_dh;
+	} else {
+		struct scsi_device_handler *tmp_dh;
+
+		spin_lock(&list_lock);
+		list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
+			if (scsi_dh_handler_lookup(tmp_dh, sdev))
+				found_dh = tmp_dh;
+		}
+		spin_unlock(&list_lock);
+	}
+
+	if (found_dh) { /* If device is found, add it to the cache */
+		tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+		if (tmp) {
+			strncpy(tmp->vendor, sdev->vendor, 8);
+			strncpy(tmp->model, sdev->model, 16);
+			tmp->vendor[8] = '\0';
+			tmp->model[16] = '\0';
+			tmp->handler = found_dh;
+			spin_lock(&list_lock);
+			list_add(&tmp->node, &scsi_dh_dev_list);
+			spin_unlock(&list_lock);
+		} else {
+			found_dh = NULL;
+		}
+	}
+
+	return found_dh;
+}
+
+/*
+ * scsi_dh_handler_attach - Attach a device handler to a device
+ * @sdev - SCSI device the device handler should attach to
+ * @scsi_dh - The device handler to attach
+ */
+static int scsi_dh_handler_attach(struct scsi_device *sdev,
+				  struct scsi_device_handler *scsi_dh)
+{
+	int err = 0;
+
+	if (sdev->scsi_dh_data) {
+		if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
+			err = -EBUSY;
+	} else if (scsi_dh->attach)
+		err = scsi_dh->attach(sdev);
+
+	return err;
+}
+
+/*
+ * scsi_dh_handler_detach - Detach a device handler from a device
+ * @sdev - SCSI device the device handler should be detached from
+ * @scsi_dh - Device handler to be detached
+ *
+ * Detach from a device handler. If a device handler is specified,
+ * only detach if the currently attached handler matches @scsi_dh.
+ */
+static void scsi_dh_handler_detach(struct scsi_device *sdev,
+				   struct scsi_device_handler *scsi_dh)
+{
+	if (!sdev->scsi_dh_data)
+		return;
+
+	if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
+		return;
+
+	if (!scsi_dh)
+		scsi_dh = sdev->scsi_dh_data->scsi_dh;
+
+	if (scsi_dh && scsi_dh->detach)
+		scsi_dh->detach(sdev);
+}
+
+/*
+ * Functions for sysfs attribute 'dh_state'
+ */
+static ssize_t
+store_dh_state(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_device_handler *scsi_dh;
+	int err = -EINVAL;
+
+	if (!sdev->scsi_dh_data) {
+		/*
+		 * Attach to a device handler
+		 */
+		if (!(scsi_dh = get_device_handler(buf)))
+			return err;
+		err = scsi_dh_handler_attach(sdev, scsi_dh);
+	} else {
+		scsi_dh = sdev->scsi_dh_data->scsi_dh;
+		if (!strncmp(buf, "detach", 6)) {
+			/*
+			 * Detach from a device handler
+			 */
+			scsi_dh_handler_detach(sdev, scsi_dh);
+			err = 0;
+		} else if (!strncmp(buf, "activate", 8)) {
+			/*
+			 * Activate a device handler
+			 */
+			if (scsi_dh->activate)
+				err = scsi_dh->activate(sdev);
+			else
+				err = 0;
+		}
+	}
+
+	return err<0?err:count;
+}
+
+static ssize_t
+show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+
+	if (!sdev->scsi_dh_data)
+		return snprintf(buf, 20, "detached\n");
+
+	return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
+}
+
+static struct device_attribute scsi_dh_state_attr =
+	__ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
+	       store_dh_state);
+
+/*
+ * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
+ */
+static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
+{
+	struct scsi_device *sdev;
+	int err;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	err = device_create_file(&sdev->sdev_gendev,
+				 &scsi_dh_state_attr);
+
+	return 0;
+}
+
+/*
+ * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
+ */
+static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
+{
+	struct scsi_device *sdev;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	device_remove_file(&sdev->sdev_gendev,
+			   &scsi_dh_state_attr);
+
+	return 0;
+}
+
+/*
+ * scsi_dh_notifier - notifier chain callback
+ */
+static int scsi_dh_notifier(struct notifier_block *nb,
+			    unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct scsi_device *sdev;
+	int err = 0;
+	struct scsi_device_handler *devinfo = NULL;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	if (action == BUS_NOTIFY_ADD_DEVICE) {
+		devinfo = device_handler_match(NULL, sdev);
+		if (!devinfo)
+			goto out;
+
+		err = scsi_dh_handler_attach(sdev, devinfo);
+		if (!err)
+			err = device_create_file(dev, &scsi_dh_state_attr);
+	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
+		device_remove_file(dev, &scsi_dh_state_attr);
+		scsi_dh_handler_detach(sdev, NULL);
+	}
+out:
+	return err;
+}
+
+/*
+ * scsi_dh_notifier_add - Callback for scsi_register_device_handler
+ */
 static int scsi_dh_notifier_add(struct device *dev, void *data)
 static int scsi_dh_notifier_add(struct device *dev, void *data)
 {
 {
 	struct scsi_device_handler *scsi_dh = data;
 	struct scsi_device_handler *scsi_dh = data;
+	struct scsi_device *sdev;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	if (!get_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	if (device_handler_match(scsi_dh, sdev))
+		scsi_dh_handler_attach(sdev, scsi_dh);
+
+	put_device(dev);
+
+	return 0;
+}
+
+/*
+ * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
+ */
+static int scsi_dh_notifier_remove(struct device *dev, void *data)
+{
+	struct scsi_device_handler *scsi_dh = data;
+	struct scsi_device *sdev;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	if (!get_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	scsi_dh_handler_detach(sdev, scsi_dh);
+
+	put_device(dev);
 
 
-	scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -59,33 +363,19 @@ static int scsi_dh_notifier_add(struct device *dev, void *data)
  */
  */
 int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
 int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
 {
 {
-	int ret = -EBUSY;
-	struct scsi_device_handler *tmp;
+	if (get_device_handler(scsi_dh->name))
+		return -EBUSY;
 
 
-	tmp = get_device_handler(scsi_dh->name);
-	if (tmp)
-		goto done;
-
-	ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb);
-
-	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
 	spin_lock(&list_lock);
 	spin_lock(&list_lock);
 	list_add(&scsi_dh->list, &scsi_dh_list);
 	list_add(&scsi_dh->list, &scsi_dh_list);
 	spin_unlock(&list_lock);
 	spin_unlock(&list_lock);
+	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
+	printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
 
 
-done:
-	return ret;
+	return SCSI_DH_OK;
 }
 }
 EXPORT_SYMBOL_GPL(scsi_register_device_handler);
 EXPORT_SYMBOL_GPL(scsi_register_device_handler);
 
 
-static int scsi_dh_notifier_remove(struct device *dev, void *data)
-{
-	struct scsi_device_handler *scsi_dh = data;
-
-	scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev);
-	return 0;
-}
-
 /*
 /*
  * scsi_unregister_device_handler - register a device handler personality
  * scsi_unregister_device_handler - register a device handler personality
  *      module.
  *      module.
@@ -95,23 +385,26 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
  */
  */
 int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
 int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
 {
 {
-	int ret = -ENODEV;
-	struct scsi_device_handler *tmp;
-
-	tmp = get_device_handler(scsi_dh->name);
-	if (!tmp)
-		goto done;
+	struct scsi_dh_devinfo_list *tmp, *pos;
 
 
-	ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb);
+	if (!get_device_handler(scsi_dh->name))
+		return -ENODEV;
 
 
 	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
 	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
-					scsi_dh_notifier_remove);
+			 scsi_dh_notifier_remove);
+
 	spin_lock(&list_lock);
 	spin_lock(&list_lock);
 	list_del(&scsi_dh->list);
 	list_del(&scsi_dh->list);
+	list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) {
+		if (pos->handler == scsi_dh) {
+			list_del(&pos->node);
+			kfree(pos);
+		}
+	}
 	spin_unlock(&list_lock);
 	spin_unlock(&list_lock);
+	printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
 
 
-done:
-	return ret;
+	return SCSI_DH_OK;
 }
 }
 EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
 EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
 
 
@@ -157,6 +450,97 @@ int scsi_dh_handler_exist(const char *name)
 }
 }
 EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
 EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
 
 
+/*
+ * scsi_dh_handler_attach - Attach device handler
+ * @sdev - sdev the handler should be attached to
+ * @name - name of the handler to attach
+ */
+int scsi_dh_attach(struct request_queue *q, const char *name)
+{
+	unsigned long flags;
+	struct scsi_device *sdev;
+	struct scsi_device_handler *scsi_dh;
+	int err = 0;
+
+	scsi_dh = get_device_handler(name);
+	if (!scsi_dh)
+		return -EINVAL;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	sdev = q->queuedata;
+	if (!sdev || !get_device(&sdev->sdev_gendev))
+		err = -ENODEV;
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	if (!err) {
+		err = scsi_dh_handler_attach(sdev, scsi_dh);
+
+		put_device(&sdev->sdev_gendev);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_attach);
+
+/*
+ * scsi_dh_handler_detach - Detach device handler
+ * @sdev - sdev the handler should be detached from
+ *
+ * This function will detach the device handler only
+ * if the sdev is not part of the internal list, ie
+ * if it has been attached manually.
+ */
+void scsi_dh_detach(struct request_queue *q)
+{
+	unsigned long flags;
+	struct scsi_device *sdev;
+	struct scsi_device_handler *scsi_dh = NULL;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	sdev = q->queuedata;
+	if (!sdev || !get_device(&sdev->sdev_gendev))
+		sdev = NULL;
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	if (!sdev)
+		return;
+
+	if (sdev->scsi_dh_data) {
+		/* if sdev is not on internal list, detach */
+		scsi_dh = sdev->scsi_dh_data->scsi_dh;
+		if (!device_handler_match(scsi_dh, sdev))
+			scsi_dh_handler_detach(sdev, scsi_dh);
+	}
+	put_device(&sdev->sdev_gendev);
+}
+EXPORT_SYMBOL_GPL(scsi_dh_detach);
+
+static struct notifier_block scsi_dh_nb = {
+	.notifier_call = scsi_dh_notifier
+};
+
+static int __init scsi_dh_init(void)
+{
+	int r;
+
+	r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
+
+	if (!r)
+		bus_for_each_dev(&scsi_bus_type, NULL, NULL,
+				 scsi_dh_sysfs_attr_add);
+
+	return r;
+}
+
+static void __exit scsi_dh_exit(void)
+{
+	bus_for_each_dev(&scsi_bus_type, NULL, NULL,
+			 scsi_dh_sysfs_attr_remove);
+	bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
+}
+
+module_init(scsi_dh_init);
+module_exit(scsi_dh_exit);
+
 MODULE_DESCRIPTION("SCSI device handler");
 MODULE_DESCRIPTION("SCSI device handler");
 MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
 MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 802 - 0
drivers/scsi/device_handler/scsi_dh_alua.c

@@ -0,0 +1,802 @@
+/*
+ * Generic SCSI-3 ALUA SCSI Device Handler
+ *
+ * Copyright (C) 2007, 2008 Hannes Reinecke, SUSE Linux Products GmbH.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_dh.h>
+
+#define ALUA_DH_NAME "alua"
+#define ALUA_DH_VER "1.2"
+
+#define TPGS_STATE_OPTIMIZED		0x0
+#define TPGS_STATE_NONOPTIMIZED		0x1
+#define TPGS_STATE_STANDBY		0x2
+#define TPGS_STATE_UNAVAILABLE		0x3
+#define TPGS_STATE_OFFLINE		0xe
+#define TPGS_STATE_TRANSITIONING	0xf
+
+#define TPGS_SUPPORT_NONE		0x00
+#define TPGS_SUPPORT_OPTIMIZED		0x01
+#define TPGS_SUPPORT_NONOPTIMIZED	0x02
+#define TPGS_SUPPORT_STANDBY		0x04
+#define TPGS_SUPPORT_UNAVAILABLE	0x08
+#define TPGS_SUPPORT_OFFLINE		0x40
+#define TPGS_SUPPORT_TRANSITION		0x80
+
+#define TPGS_MODE_UNINITIALIZED		 -1
+#define TPGS_MODE_NONE			0x0
+#define TPGS_MODE_IMPLICIT		0x1
+#define TPGS_MODE_EXPLICIT		0x2
+
+#define ALUA_INQUIRY_SIZE		36
+#define ALUA_FAILOVER_TIMEOUT		(60 * HZ)
+#define ALUA_FAILOVER_RETRIES		5
+
+struct alua_dh_data {
+	int			group_id;
+	int			rel_port;
+	int			tpgs;
+	int			state;
+	unsigned char		inq[ALUA_INQUIRY_SIZE];
+	unsigned char		*buff;
+	int			bufflen;
+	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
+	int			senselen;
+};
+
+#define ALUA_POLICY_SWITCH_CURRENT	0
+#define ALUA_POLICY_SWITCH_ALL		1
+
+static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
+	BUG_ON(scsi_dh_data == NULL);
+	return ((struct alua_dh_data *) scsi_dh_data->buf);
+}
+
+static int realloc_buffer(struct alua_dh_data *h, unsigned len)
+{
+	if (h->buff && h->buff != h->inq)
+		kfree(h->buff);
+
+	h->buff = kmalloc(len, GFP_NOIO);
+	if (!h->buff) {
+		h->buff = h->inq;
+		h->bufflen = ALUA_INQUIRY_SIZE;
+		return 1;
+	}
+	h->bufflen = len;
+	return 0;
+}
+
+static struct request *get_alua_req(struct scsi_device *sdev,
+				    void *buffer, unsigned buflen, int rw)
+{
+	struct request *rq;
+	struct request_queue *q = sdev->request_queue;
+
+	rq = blk_get_request(q, rw, GFP_NOIO);
+
+	if (!rq) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: blk_get_request failed\n", __func__);
+		return NULL;
+	}
+
+	if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
+		blk_put_request(rq);
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: blk_rq_map_kern failed\n", __func__);
+		return NULL;
+	}
+
+	rq->cmd_type = REQ_TYPE_BLOCK_PC;
+	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
+	rq->retries = ALUA_FAILOVER_RETRIES;
+	rq->timeout = ALUA_FAILOVER_TIMEOUT;
+
+	return rq;
+}
+
+/*
+ * submit_std_inquiry - Issue a standard INQUIRY command
+ * @sdev: sdev the command should be send to
+ */
+static int submit_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+
+	rq = get_alua_req(sdev, h->inq, ALUA_INQUIRY_SIZE, READ);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = INQUIRY;
+	rq->cmd[1] = 0;
+	rq->cmd[2] = 0;
+	rq->cmd[4] = ALUA_INQUIRY_SIZE;
+	rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: std inquiry failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
+ * @sdev: sdev the command should be sent to
+ */
+static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+
+	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = INQUIRY;
+	rq->cmd[1] = 1;
+	rq->cmd[2] = 0x83;
+	rq->cmd[4] = h->bufflen;
+	rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: evpd inquiry failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
+ * @sdev: sdev the command should be sent to
+ */
+static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+
+	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = MAINTENANCE_IN;
+	rq->cmd[1] = MI_REPORT_TARGET_PGS;
+	rq->cmd[6] = (h->bufflen >> 24) & 0xff;
+	rq->cmd[7] = (h->bufflen >> 16) & 0xff;
+	rq->cmd[8] = (h->bufflen >>  8) & 0xff;
+	rq->cmd[9] = h->bufflen & 0xff;
+	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: rtpg failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * submit_stpg - Issue a SET TARGET GROUP STATES command
+ * @sdev: sdev the command should be sent to
+ *
+ * Currently we're only setting the current target port group state
+ * to 'active/optimized' and let the array firmware figure out
+ * the states of the remaining groups.
+ */
+static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+	int stpg_len = 8;
+
+	/* Prepare the data buffer */
+	memset(h->buff, 0, stpg_len);
+	h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+	h->buff[6] = (h->group_id >> 8) & 0x0f;
+	h->buff[7] = h->group_id & 0x0f;
+
+	rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = MAINTENANCE_OUT;
+	rq->cmd[1] = MO_SET_TARGET_PGS;
+	rq->cmd[6] = (stpg_len >> 24) & 0xff;
+	rq->cmd[7] = (stpg_len >> 16) & 0xff;
+	rq->cmd[8] = (stpg_len >>  8) & 0xff;
+	rq->cmd[9] = stpg_len & 0xff;
+	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: stpg failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * alua_std_inquiry - Evaluate standard INQUIRY command
+ * @sdev: device to be checked
+ *
+ * Just extract the TPGS setting to find out if ALUA
+ * is supported.
+ */
+static int alua_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	int err;
+
+	err = submit_std_inquiry(sdev, h);
+
+	if (err != SCSI_DH_OK)
+		return err;
+
+	/* Check TPGS setting */
+	h->tpgs = (h->inq[5] >> 4) & 0x3;
+	switch (h->tpgs) {
+	case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: supports implicit and explicit TPGS\n",
+			    ALUA_DH_NAME);
+		break;
+	case TPGS_MODE_EXPLICIT:
+		sdev_printk(KERN_INFO, sdev, "%s: supports explicit TPGS\n",
+			    ALUA_DH_NAME);
+		break;
+	case TPGS_MODE_IMPLICIT:
+		sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
+			    ALUA_DH_NAME);
+		break;
+	default:
+		h->tpgs = TPGS_MODE_NONE;
+		sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
+			    ALUA_DH_NAME);
+		err = SCSI_DH_DEV_UNSUPP;
+		break;
+	}
+
+	return err;
+}
+
+/*
+ * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * @sdev: device to be checked
+ *
+ * Extract the relative target port and the target port group
+ * descriptor from the list of identificators.
+ */
+static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	int len;
+	unsigned err;
+	unsigned char *d;
+
+ retry:
+	err = submit_vpd_inquiry(sdev, h);
+
+	if (err != SCSI_DH_OK)
+		return err;
+
+	/* Check if vpd page exceeds initial buffer */
+	len = (h->buff[2] << 8) + h->buff[3] + 4;
+	if (len > h->bufflen) {
+		/* Resubmit with the correct length */
+		if (realloc_buffer(h, len)) {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: kmalloc buffer failed\n",
+				    ALUA_DH_NAME);
+			/* Temporary failure, bypass */
+			return SCSI_DH_DEV_TEMP_BUSY;
+		}
+		goto retry;
+	}
+
+	/*
+	 * Now look for the correct descriptor.
+	 */
+	d = h->buff + 4;
+	while (d < h->buff + len) {
+		switch (d[1] & 0xf) {
+		case 0x4:
+			/* Relative target port */
+			h->rel_port = (d[6] << 8) + d[7];
+			break;
+		case 0x5:
+			/* Target port group */
+			h->group_id = (d[6] << 8) + d[7];
+			break;
+		default:
+			break;
+		}
+		d += d[3] + 4;
+	}
+
+	if (h->group_id == -1) {
+		/*
+		 * Internal error; TPGS supported but required
+		 * VPD identification descriptors not present.
+		 * Disable ALUA support
+		 */
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: No target port descriptors found\n",
+			    ALUA_DH_NAME);
+		h->state = TPGS_STATE_OPTIMIZED;
+		h->tpgs = TPGS_MODE_NONE;
+		err = SCSI_DH_DEV_UNSUPP;
+	} else {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: port group %02x rel port %02x\n",
+			    ALUA_DH_NAME, h->group_id, h->rel_port);
+	}
+
+	return err;
+}
+
+static char print_alua_state(int state)
+{
+	switch (state) {
+	case TPGS_STATE_OPTIMIZED:
+		return 'A';
+	case TPGS_STATE_NONOPTIMIZED:
+		return 'N';
+	case TPGS_STATE_STANDBY:
+		return 'S';
+	case TPGS_STATE_UNAVAILABLE:
+		return 'U';
+	case TPGS_STATE_OFFLINE:
+		return 'O';
+	case TPGS_STATE_TRANSITIONING:
+		return 'T';
+	default:
+		return 'X';
+	}
+}
+
+static int alua_check_sense(struct scsi_device *sdev,
+			    struct scsi_sense_hdr *sense_hdr)
+{
+	switch (sense_hdr->sense_key) {
+	case NOT_READY:
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+			/*
+			 * LUN Not Accessible - ALUA state transition
+			 */
+			return NEEDS_RETRY;
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
+			/*
+			 * LUN Not Accessible -- Target port in standby state
+			 */
+			return SUCCESS;
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
+			/*
+			 * LUN Not Accessible -- Target port in unavailable state
+			 */
+			return SUCCESS;
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
+			/*
+			 * LUN Not Ready -- Offline
+			 */
+			return SUCCESS;
+		break;
+	case UNIT_ATTENTION:
+		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+			/*
+			 * Power On, Reset, or Bus Device Reset, just retry.
+			 */
+			return NEEDS_RETRY;
+		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
+			/*
+			 * ALUA state changed
+			 */
+			return NEEDS_RETRY;
+		}
+		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
+			/*
+			 * Implicit ALUA state transition failed
+			 */
+			return NEEDS_RETRY;
+		}
+		break;
+	}
+
+	return SCSI_RETURN_NOT_HANDLED;
+}
+
+/*
+ * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * @sdev: the device to be evaluated
+ * @state: the new target group state
+ *
+ * Send a SET TARGET GROUP STATES command to the device.
+ * We only have to test here if we should resubmit the command;
+ * any other error is assumed as a failure.
+ */
+static int alua_stpg(struct scsi_device *sdev, int state,
+		     struct alua_dh_data *h)
+{
+	struct scsi_sense_hdr sense_hdr;
+	unsigned err;
+	int retry = ALUA_FAILOVER_RETRIES;
+
+ retry:
+	err = submit_stpg(sdev, h);
+	if (err == SCSI_DH_IO && h->senselen > 0) {
+		err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+					   &sense_hdr);
+		if (!err)
+			return SCSI_DH_IO;
+		err = alua_check_sense(sdev, &sense_hdr);
+		if (retry > 0 && err == NEEDS_RETRY) {
+			retry--;
+			goto retry;
+		}
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: stpg sense code: %02x/%02x/%02x\n",
+			    ALUA_DH_NAME, sense_hdr.sense_key,
+			    sense_hdr.asc, sense_hdr.ascq);
+		err = SCSI_DH_IO;
+	}
+	if (err == SCSI_DH_OK) {
+		h->state = state;
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: port group %02x switched to state %c\n",
+			    ALUA_DH_NAME, h->group_id,
+			    print_alua_state(h->state) );
+	}
+	return err;
+}
+
+/*
+ * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
+ * @sdev: the device to be evaluated.
+ *
+ * Evaluate the Target Port Group State.
+ * Returns SCSI_DH_DEV_OFFLINED if the path is
+ * found to be unuseable.
+ */
+static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct scsi_sense_hdr sense_hdr;
+	int len, k, off, valid_states = 0;
+	char *ucp;
+	unsigned err;
+
+ retry:
+	err = submit_rtpg(sdev, h);
+
+	if (err == SCSI_DH_IO && h->senselen > 0) {
+		err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+					   &sense_hdr);
+		if (!err)
+			return SCSI_DH_IO;
+
+		err = alua_check_sense(sdev, &sense_hdr);
+		if (err == NEEDS_RETRY)
+			goto retry;
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: rtpg sense code %02x/%02x/%02x\n",
+			    ALUA_DH_NAME, sense_hdr.sense_key,
+			    sense_hdr.asc, sense_hdr.ascq);
+		err = SCSI_DH_IO;
+	}
+	if (err != SCSI_DH_OK)
+		return err;
+
+	len = (h->buff[0] << 24) + (h->buff[1] << 16) +
+		(h->buff[2] << 8) + h->buff[3] + 4;
+
+	if (len > h->bufflen) {
+		/* Resubmit with the correct length */
+		if (realloc_buffer(h, len)) {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: kmalloc buffer failed\n",__func__);
+			/* Temporary failure, bypass */
+			return SCSI_DH_DEV_TEMP_BUSY;
+		}
+		goto retry;
+	}
+
+	for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) {
+		if (h->group_id == (ucp[2] << 8) + ucp[3]) {
+			h->state = ucp[0] & 0x0f;
+			valid_states = ucp[1];
+		}
+		off = 8 + (ucp[7] * 4);
+	}
+
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: port group %02x state %c supports %c%c%c%c%c%c\n",
+		    ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
+		    valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
+		    valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
+		    valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u',
+		    valid_states&TPGS_SUPPORT_STANDBY?'S':'s',
+		    valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
+		    valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
+
+	if (h->tpgs & TPGS_MODE_EXPLICIT) {
+		switch (h->state) {
+		case TPGS_STATE_TRANSITIONING:
+			/* State transition, retry */
+			goto retry;
+			break;
+		case TPGS_STATE_OFFLINE:
+			/* Path is offline, fail */
+			err = SCSI_DH_DEV_OFFLINED;
+			break;
+		default:
+			break;
+		}
+	} else {
+		/* Only Implicit ALUA support */
+		if (h->state == TPGS_STATE_OPTIMIZED ||
+		    h->state == TPGS_STATE_NONOPTIMIZED ||
+		    h->state == TPGS_STATE_STANDBY)
+			/* Useable path if active */
+			err = SCSI_DH_OK;
+		else
+			/* Path unuseable for unavailable/offline */
+			err = SCSI_DH_DEV_OFFLINED;
+	}
+	return err;
+}
+
+/*
+ * alua_initialize - Initialize ALUA state
+ * @sdev: the device to be initialized
+ *
+ * For the prep_fn to work correctly we have
+ * to initialize the ALUA state for the device.
+ */
+static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	int err;
+
+	err = alua_std_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto out;
+
+	err = alua_vpd_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto out;
+
+	err = alua_rtpg(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto out;
+
+out:
+	return err;
+}
+
+/*
+ * alua_activate - activate a path
+ * @sdev: device on the path to be activated
+ *
+ * We're currently switching the port group to be activated only and
+ * let the array figure out the rest.
+ * There may be other arrays which require us to switch all port groups
+ * based on a certain policy. But until we actually encounter them it
+ * should be okay.
+ */
+static int alua_activate(struct scsi_device *sdev)
+{
+	struct alua_dh_data *h = get_alua_data(sdev);
+	int err = SCSI_DH_OK;
+
+	if (h->group_id != -1) {
+		err = alua_rtpg(sdev, h);
+		if (err != SCSI_DH_OK)
+			goto out;
+	}
+
+	if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
+		err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
+
+out:
+	return err;
+}
+
+/*
+ * alua_prep_fn - request callback
+ *
+ * Fail I/O to all paths not in state
+ * active/optimized or active/non-optimized.
+ */
+static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
+{
+	struct alua_dh_data *h = get_alua_data(sdev);
+	int ret = BLKPREP_OK;
+
+	if (h->state != TPGS_STATE_OPTIMIZED &&
+	    h->state != TPGS_STATE_NONOPTIMIZED) {
+		ret = BLKPREP_KILL;
+		req->cmd_flags |= REQ_QUIET;
+	}
+	return ret;
+
+}
+
+const struct scsi_dh_devlist alua_dev_list[] = {
+	{"HP", "MSA VOLUME" },
+	{"HP", "HSV101" },
+	{"HP", "HSV111" },
+	{"HP", "HSV200" },
+	{"HP", "HSV210" },
+	{"HP", "HSV300" },
+	{"IBM", "2107900" },
+	{"IBM", "2145" },
+	{"Pillar", "Axiom" },
+	{NULL, NULL}
+};
+
+static int alua_bus_attach(struct scsi_device *sdev);
+static void alua_bus_detach(struct scsi_device *sdev);
+
+static struct scsi_device_handler alua_dh = {
+	.name = ALUA_DH_NAME,
+	.module = THIS_MODULE,
+	.devlist = alua_dev_list,
+	.attach = alua_bus_attach,
+	.detach = alua_bus_detach,
+	.prep_fn = alua_prep_fn,
+	.check_sense = alua_check_sense,
+	.activate = alua_activate,
+};
+
+/*
+ * alua_bus_attach - Attach device handler
+ * @sdev: device to be attached to
+ */
+static int alua_bus_attach(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data;
+	struct alua_dh_data *h;
+	unsigned long flags;
+	int err = SCSI_DH_OK;
+
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(*h) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
+			    ALUA_DH_NAME);
+		return -ENOMEM;
+	}
+
+	scsi_dh_data->scsi_dh = &alua_dh;
+	h = (struct alua_dh_data *) scsi_dh_data->buf;
+	h->tpgs = TPGS_MODE_UNINITIALIZED;
+	h->state = TPGS_STATE_OPTIMIZED;
+	h->group_id = -1;
+	h->rel_port = -1;
+	h->buff = h->inq;
+	h->bufflen = ALUA_INQUIRY_SIZE;
+
+	err = alua_initialize(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
+
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	return 0;
+
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n", ALUA_DH_NAME);
+	return -EINVAL;
+}
+
+/*
+ * alua_bus_detach - Detach device handler
+ * @sdev: device to be detached from
+ */
+static void alua_bus_detach(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data;
+	struct alua_dh_data *h;
+	unsigned long flags;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	h = (struct alua_dh_data *) scsi_dh_data->buf;
+	if (h->buff && h->inq != h->buff)
+		kfree(h->buff);
+	kfree(scsi_dh_data);
+	module_put(THIS_MODULE);
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", ALUA_DH_NAME);
+}
+
+static int __init alua_init(void)
+{
+	int r;
+
+	r = scsi_register_device_handler(&alua_dh);
+	if (r != 0)
+		printk(KERN_ERR "%s: Failed to register scsi device handler",
+			ALUA_DH_NAME);
+	return r;
+}
+
+static void __exit alua_exit(void)
+{
+	scsi_unregister_device_handler(&alua_dh);
+}
+
+module_init(alua_init);
+module_exit(alua_exit);
+
+MODULE_DESCRIPTION("DM Multipath ALUA support");
+MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ALUA_DH_VER);

+ 409 - 235
drivers/scsi/device_handler/scsi_dh_emc.c

@@ -25,28 +25,31 @@
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_device.h>
 
 
-#define CLARIION_NAME			"emc_clariion"
+#define CLARIION_NAME			"emc"
 
 
 #define CLARIION_TRESPASS_PAGE		0x22
 #define CLARIION_TRESPASS_PAGE		0x22
-#define CLARIION_BUFFER_SIZE		0x80
+#define CLARIION_BUFFER_SIZE		0xFC
 #define CLARIION_TIMEOUT		(60 * HZ)
 #define CLARIION_TIMEOUT		(60 * HZ)
 #define CLARIION_RETRIES		3
 #define CLARIION_RETRIES		3
 #define CLARIION_UNBOUND_LU		-1
 #define CLARIION_UNBOUND_LU		-1
+#define CLARIION_SP_A			0
+#define CLARIION_SP_B			1
 
 
-static unsigned char long_trespass[] = {
-	0, 0, 0, 0,
-	CLARIION_TRESPASS_PAGE,	/* Page code */
-	0x09,			/* Page length - 2 */
-	0x81,			/* Trespass code + Honor reservation bit */
-	0xff, 0xff,		/* Trespass target */
-	0, 0, 0, 0, 0, 0	/* Reserved bytes / unknown */
-};
+/* Flags */
+#define CLARIION_SHORT_TRESPASS		1
+#define CLARIION_HONOR_RESERVATIONS	2
 
 
-static unsigned char long_trespass_hr[] = {
-	0, 0, 0, 0,
+/* LUN states */
+#define CLARIION_LUN_UNINITIALIZED	-1
+#define CLARIION_LUN_UNBOUND		0
+#define CLARIION_LUN_BOUND		1
+#define CLARIION_LUN_OWNED		2
+
+static unsigned char long_trespass[] = {
+	0, 0, 0, 0, 0, 0, 0, 0,
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	0x09,			/* Page length - 2 */
 	0x09,			/* Page length - 2 */
-	0x01,			/* Trespass code + Honor reservation bit */
+	0x01,			/* Trespass code */
 	0xff, 0xff,		/* Trespass target */
 	0xff, 0xff,		/* Trespass target */
 	0, 0, 0, 0, 0, 0	/* Reserved bytes / unknown */
 	0, 0, 0, 0, 0, 0	/* Reserved bytes / unknown */
 };
 };
@@ -55,39 +58,56 @@ static unsigned char short_trespass[] = {
 	0, 0, 0, 0,
 	0, 0, 0, 0,
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	0x02,			/* Page length - 2 */
 	0x02,			/* Page length - 2 */
-	0x81,			/* Trespass code + Honor reservation bit */
+	0x01,			/* Trespass code */
 	0xff,			/* Trespass target */
 	0xff,			/* Trespass target */
 };
 };
 
 
-static unsigned char short_trespass_hr[] = {
-	0, 0, 0, 0,
-	CLARIION_TRESPASS_PAGE,	/* Page code */
-	0x02,			/* Page length - 2 */
-	0x01,			/* Trespass code + Honor reservation bit */
-	0xff,			/* Trespass target */
+static const char * lun_state[] =
+{
+    "not bound",
+    "bound",
+    "owned",
 };
 };
 
 
 struct clariion_dh_data {
 struct clariion_dh_data {
 	/*
 	/*
+	 * Flags:
+	 *  CLARIION_SHORT_TRESPASS
 	 * Use short trespass command (FC-series) or the long version
 	 * Use short trespass command (FC-series) or the long version
 	 * (default for AX/CX CLARiiON arrays).
 	 * (default for AX/CX CLARiiON arrays).
-	 */
-	unsigned short_trespass;
-	/*
+	 *
+	 *  CLARIION_HONOR_RESERVATIONS
 	 * Whether or not (default) to honor SCSI reservations when
 	 * Whether or not (default) to honor SCSI reservations when
 	 * initiating a switch-over.
 	 * initiating a switch-over.
 	 */
 	 */
-	unsigned hr;
-	/* I/O buffer for both MODE_SELECT and INQUIRY commands. */
+	unsigned flags;
+	/*
+	 * I/O buffer for both MODE_SELECT and INQUIRY commands.
+	 */
 	char buffer[CLARIION_BUFFER_SIZE];
 	char buffer[CLARIION_BUFFER_SIZE];
 	/*
 	/*
 	 * SCSI sense buffer for commands -- assumes serial issuance
 	 * SCSI sense buffer for commands -- assumes serial issuance
 	 * and completion sequence of all commands for same multipath.
 	 * and completion sequence of all commands for same multipath.
 	 */
 	 */
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
-	/* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */
+	unsigned int senselen;
+	/*
+	 * LUN state
+	 */
+	int lun_state;
+	/*
+	 * SP Port number
+	 */
+	int port;
+	/*
+	 * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this
+	 * path's mapped LUN
+	 */
 	int default_sp;
 	int default_sp;
-	/* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */
+	/*
+	 * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this
+	 * path's mapped LUN
+	 */
 	int current_sp;
 	int current_sp;
 };
 };
 
 
@@ -102,19 +122,16 @@ static inline struct clariion_dh_data
 /*
 /*
  * Parse MODE_SELECT cmd reply.
  * Parse MODE_SELECT cmd reply.
  */
  */
-static int trespass_endio(struct scsi_device *sdev, int result)
+static int trespass_endio(struct scsi_device *sdev, char *sense)
 {
 {
-	int err = SCSI_DH_OK;
+	int err = SCSI_DH_IO;
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
-	char *sense = csdev->sense;
 
 
-	if (status_byte(result) == CHECK_CONDITION &&
-	    scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
-		sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, "
+	if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
+		sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
 			    "0x%2x, 0x%2x while sending CLARiiON trespass "
 			    "0x%2x, 0x%2x while sending CLARiiON trespass "
-			    "command.\n", sshdr.sense_key, sshdr.asc,
-			     sshdr.ascq);
+			    "command.\n", CLARIION_NAME, sshdr.sense_key,
+			    sshdr.asc, sshdr.ascq);
 
 
 		if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
 		if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
 		     (sshdr.ascq == 0x00)) {
 		     (sshdr.ascq == 0x00)) {
@@ -122,9 +139,9 @@ static int trespass_endio(struct scsi_device *sdev, int result)
 			 * Array based copy in progress -- do not send
 			 * Array based copy in progress -- do not send
 			 * mode_select or copy will be aborted mid-stream.
 			 * mode_select or copy will be aborted mid-stream.
 			 */
 			 */
-			sdev_printk(KERN_INFO, sdev, "Array Based Copy in "
+			sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
 				    "progress while sending CLARiiON trespass "
 				    "progress while sending CLARiiON trespass "
-				    "command.\n");
+				    "command.\n", CLARIION_NAME);
 			err = SCSI_DH_DEV_TEMP_BUSY;
 			err = SCSI_DH_DEV_TEMP_BUSY;
 		} else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
 		} else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
 			    (sshdr.ascq == 0x03)) {
 			    (sshdr.ascq == 0x03)) {
@@ -132,160 +149,153 @@ static int trespass_endio(struct scsi_device *sdev, int result)
 			 * LUN Not Ready - Manual Intervention Required
 			 * LUN Not Ready - Manual Intervention Required
 			 * indicates in-progress ucode upgrade (NDU).
 			 * indicates in-progress ucode upgrade (NDU).
 			 */
 			 */
-			sdev_printk(KERN_INFO, sdev, "Detected in-progress "
+			sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
 				    "ucode upgrade NDU operation while sending "
 				    "ucode upgrade NDU operation while sending "
-				    "CLARiiON trespass command.\n");
+				    "CLARiiON trespass command.\n", CLARIION_NAME);
 			err = SCSI_DH_DEV_TEMP_BUSY;
 			err = SCSI_DH_DEV_TEMP_BUSY;
 		} else
 		} else
 			err = SCSI_DH_DEV_FAILED;
 			err = SCSI_DH_DEV_FAILED;
-	} else if (result) {
-		sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending "
-			    "CLARiiON trespass command.\n", result);
-		err = SCSI_DH_IO;
+	} else {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: failed to send MODE SELECT, no sense available\n",
+			    CLARIION_NAME);
 	}
 	}
-
 	return err;
 	return err;
 }
 }
 
 
-static int parse_sp_info_reply(struct scsi_device *sdev, int result,
-		int *default_sp, int *current_sp, int *new_current_sp)
+static int parse_sp_info_reply(struct scsi_device *sdev,
+			       struct clariion_dh_data *csdev)
 {
 {
 	int err = SCSI_DH_OK;
 	int err = SCSI_DH_OK;
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
 
 
-	if (result == 0) {
-		/* check for in-progress ucode upgrade (NDU) */
-		if (csdev->buffer[48] != 0) {
-			sdev_printk(KERN_NOTICE, sdev, "Detected in-progress "
-			       "ucode upgrade NDU operation while finding "
-			       "current active SP.");
-			err = SCSI_DH_DEV_TEMP_BUSY;
-		} else {
-			*default_sp = csdev->buffer[5];
-
-			if (csdev->buffer[4] == 2)
-				/* SP for path is current */
-				*current_sp = csdev->buffer[8];
-			else {
-				if (csdev->buffer[4] == 1)
-					/* SP for this path is NOT current */
-					if (csdev->buffer[8] == 0)
-						*current_sp = 1;
-					else
-						*current_sp = 0;
-				else
-					/* unbound LU or LUNZ */
-					*current_sp = CLARIION_UNBOUND_LU;
-			}
-			*new_current_sp =  csdev->buffer[8];
-		}
-	} else {
-		struct scsi_sense_hdr sshdr;
-
-		err = SCSI_DH_IO;
-
-		if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
-							   &sshdr))
-			sdev_printk(KERN_ERR, sdev, "Found valid sense data "
-			      "0x%2x, 0x%2x, 0x%2x while finding current "
-			      "active SP.", sshdr.sense_key, sshdr.asc,
-			      sshdr.ascq);
-		else
-			sdev_printk(KERN_ERR, sdev, "Error 0x%x finding "
-			      "current active SP.", result);
+	/* check for in-progress ucode upgrade (NDU) */
+	if (csdev->buffer[48] != 0) {
+		sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress "
+			    "ucode upgrade NDU operation while finding "
+			    "current active SP.", CLARIION_NAME);
+		err = SCSI_DH_DEV_TEMP_BUSY;
+		goto out;
+	}
+	if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) {
+		/* Invalid buffer format */
+		sdev_printk(KERN_NOTICE, sdev,
+			    "%s: invalid VPD page 0xC0 format\n",
+			    CLARIION_NAME);
+		err = SCSI_DH_NOSYS;
+		goto out;
+	}
+	switch (csdev->buffer[28] & 0x0f) {
+	case 6:
+		sdev_printk(KERN_NOTICE, sdev,
+			    "%s: ALUA failover mode detected\n",
+			    CLARIION_NAME);
+		break;
+	case 4:
+		/* Linux failover */
+		break;
+	default:
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid failover mode %d\n",
+			    CLARIION_NAME, csdev->buffer[28] & 0x0f);
+		err = SCSI_DH_NOSYS;
+		goto out;
 	}
 	}
 
 
+	csdev->default_sp = csdev->buffer[5];
+	csdev->lun_state = csdev->buffer[4];
+	csdev->current_sp = csdev->buffer[8];
+	csdev->port = csdev->buffer[7];
+
+out:
 	return err;
 	return err;
 }
 }
 
 
-static int sp_info_endio(struct scsi_device *sdev, int result,
-					int mode_select_sent, int *done)
+#define emc_default_str "FC (Legacy)"
+
+static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer)
 {
 {
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
-	int err_flags, default_sp, current_sp, new_current_sp;
+	unsigned char len = buffer[4] + 5;
+	char *sp_model = NULL;
+	unsigned char sp_len, serial_len;
+
+	if (len < 160) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid information section length %d\n",
+			    CLARIION_NAME, len);
+		/* Check for old FC arrays */
+		if (!strncmp(buffer + 8, "DGC", 3)) {
+			/* Old FC array, not supporting extended information */
+			sp_model = emc_default_str;
+		}
+		goto out;
+	}
 
 
-	err_flags = parse_sp_info_reply(sdev, result, &default_sp,
-					     &current_sp, &new_current_sp);
+	/*
+	 * Parse extended information for SP model number
+	 */
+	serial_len = buffer[160];
+	if (serial_len == 0 || serial_len + 161 > len) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid array serial number length %d\n",
+			    CLARIION_NAME, serial_len);
+		goto out;
+	}
+	sp_len = buffer[99];
+	if (sp_len == 0 || serial_len + sp_len + 161 > len) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid model number length %d\n",
+			    CLARIION_NAME, sp_len);
+		goto out;
+	}
+	sp_model = &buffer[serial_len + 161];
+	/* Strip whitespace at the end */
+	while (sp_len > 1 && sp_model[sp_len - 1] == ' ')
+		sp_len--;
 
 
-	if (err_flags != SCSI_DH_OK)
-		goto done;
+	sp_model[sp_len] = '\0';
 
 
-	if (mode_select_sent) {
-		csdev->default_sp = default_sp;
-		csdev->current_sp = current_sp;
-	} else {
-		/*
-		 * Issue the actual module_selec request IFF either
-		 * (1) we do not know the identity of the current SP OR
-		 * (2) what we think we know is actually correct.
-		 */
-		if ((current_sp != CLARIION_UNBOUND_LU) &&
-		    (new_current_sp != current_sp)) {
-
-			csdev->default_sp = default_sp;
-			csdev->current_sp = current_sp;
-
-			sdev_printk(KERN_INFO, sdev, "Ignoring path group "
-			       "switch-over command for CLARiiON SP%s since "
-			       " mapped device is already initialized.",
-			       current_sp ? "B" : "A");
-			if (done)
-				*done = 1; /* as good as doing it */
-		}
-	}
-done:
-	return err_flags;
+out:
+	return sp_model;
 }
 }
 
 
 /*
 /*
-* Get block request for REQ_BLOCK_PC command issued to path.  Currently
-* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
-*
-* Uses data and sense buffers in hardware handler context structure and
-* assumes serial servicing of commands, both issuance and completion.
-*/
-static struct request *get_req(struct scsi_device *sdev, int cmd)
+ * Get block request for REQ_BLOCK_PC command issued to path.  Currently
+ * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
+ *
+ * Uses data and sense buffers in hardware handler context structure and
+ * assumes serial servicing of commands, both issuance and completion.
+ */
+static struct request *get_req(struct scsi_device *sdev, int cmd,
+				unsigned char *buffer)
 {
 {
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
 	struct request *rq;
 	struct request *rq;
-	unsigned char *page22;
 	int len = 0;
 	int len = 0;
 
 
 	rq = blk_get_request(sdev->request_queue,
 	rq = blk_get_request(sdev->request_queue,
-			(cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC);
+			(cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO);
 	if (!rq) {
 	if (!rq) {
 		sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
 		sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	memset(&rq->cmd, 0, BLK_MAX_CDB);
+	memset(rq->cmd, 0, BLK_MAX_CDB);
+	rq->cmd_len = COMMAND_SIZE(cmd);
 	rq->cmd[0] = cmd;
 	rq->cmd[0] = cmd;
-	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case MODE_SELECT:
 	case MODE_SELECT:
-		if (csdev->short_trespass) {
-			page22 = csdev->hr ? short_trespass_hr : short_trespass;
-			len = sizeof(short_trespass);
-		} else {
-			page22 = csdev->hr ? long_trespass_hr : long_trespass;
-			len = sizeof(long_trespass);
-		}
-		/*
-		 * Can't DMA from kernel BSS -- must copy selected trespass
-		 * command mode page contents to context buffer which is
-		 * allocated by kmalloc.
-		 */
-		BUG_ON((len > CLARIION_BUFFER_SIZE));
-		memcpy(csdev->buffer, page22, len);
+		len = sizeof(short_trespass);
+		rq->cmd_flags |= REQ_RW;
+		rq->cmd[1] = 0x10;
+		break;
+	case MODE_SELECT_10:
+		len = sizeof(long_trespass);
 		rq->cmd_flags |= REQ_RW;
 		rq->cmd_flags |= REQ_RW;
 		rq->cmd[1] = 0x10;
 		rq->cmd[1] = 0x10;
 		break;
 		break;
 	case INQUIRY:
 	case INQUIRY:
-		rq->cmd[1] = 0x1;
-		rq->cmd[2] = 0xC0;
 		len = CLARIION_BUFFER_SIZE;
 		len = CLARIION_BUFFER_SIZE;
-		memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE);
+		memset(buffer, 0, len);
 		break;
 		break;
 	default:
 	default:
 		BUG_ON(1);
 		BUG_ON(1);
@@ -298,47 +308,94 @@ static struct request *get_req(struct scsi_device *sdev, int cmd)
 	rq->timeout = CLARIION_TIMEOUT;
 	rq->timeout = CLARIION_TIMEOUT;
 	rq->retries = CLARIION_RETRIES;
 	rq->retries = CLARIION_RETRIES;
 
 
-	rq->sense = csdev->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = 0;
-
-	if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer,
-							len, GFP_ATOMIC)) {
-		__blk_put_request(rq->q, rq);
+	if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
+		blk_put_request(rq);
 		return NULL;
 		return NULL;
 	}
 	}
 
 
 	return rq;
 	return rq;
 }
 }
 
 
-static int send_cmd(struct scsi_device *sdev, int cmd)
+static int send_inquiry_cmd(struct scsi_device *sdev, int page,
+			    struct clariion_dh_data *csdev)
 {
 {
-	struct request *rq = get_req(sdev, cmd);
+	struct request *rq = get_req(sdev, INQUIRY, csdev->buffer);
+	int err;
 
 
 	if (!rq)
 	if (!rq)
 		return SCSI_DH_RES_TEMP_UNAVAIL;
 		return SCSI_DH_RES_TEMP_UNAVAIL;
 
 
-	return blk_execute_rq(sdev->request_queue, NULL, rq, 1);
+	rq->sense = csdev->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = csdev->senselen = 0;
+
+	rq->cmd[0] = INQUIRY;
+	if (page != 0) {
+		rq->cmd[1] = 1;
+		rq->cmd[2] = page;
+	}
+	err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: failed to send %s INQUIRY: %x\n",
+			    CLARIION_NAME, page?"EVPD":"standard",
+			    rq->errors);
+		csdev->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+
+	blk_put_request(rq);
+
+	return err;
 }
 }
 
 
-static int clariion_activate(struct scsi_device *sdev)
+static int send_trespass_cmd(struct scsi_device *sdev,
+			    struct clariion_dh_data *csdev)
 {
 {
-	int result, done = 0;
+	struct request *rq;
+	unsigned char *page22;
+	int err, len, cmd;
+
+	if (csdev->flags & CLARIION_SHORT_TRESPASS) {
+		page22 = short_trespass;
+		if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
+			/* Set Honor Reservations bit */
+			page22[6] |= 0x80;
+		len = sizeof(short_trespass);
+		cmd = MODE_SELECT;
+	} else {
+		page22 = long_trespass;
+		if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
+			/* Set Honor Reservations bit */
+			page22[10] |= 0x80;
+		len = sizeof(long_trespass);
+		cmd = MODE_SELECT_10;
+	}
+	BUG_ON((len > CLARIION_BUFFER_SIZE));
+	memcpy(csdev->buffer, page22, len);
 
 
-	result = send_cmd(sdev, INQUIRY);
-	result = sp_info_endio(sdev, result, 0, &done);
-	if (result || done)
-		goto done;
+	rq = get_req(sdev, cmd, csdev->buffer);
+	if (!rq)
+		return SCSI_DH_RES_TEMP_UNAVAIL;
 
 
-	result = send_cmd(sdev, MODE_SELECT);
-	result = trespass_endio(sdev, result);
-	if (result)
-		goto done;
+	rq->sense = csdev->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = csdev->senselen = 0;
 
 
-	result = send_cmd(sdev, INQUIRY);
-	result = sp_info_endio(sdev, result, 1, NULL);
-done:
-	return result;
+	err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
+	if (err == -EIO) {
+		if (rq->sense_len) {
+			err = trespass_endio(sdev, csdev->sense);
+		} else {
+			sdev_printk(KERN_INFO, sdev,
+				    "%s: failed to send MODE SELECT: %x\n",
+				    CLARIION_NAME, rq->errors);
+		}
+	}
+
+	blk_put_request(rq);
+
+	return err;
 }
 }
 
 
 static int clariion_check_sense(struct scsi_device *sdev,
 static int clariion_check_sense(struct scsi_device *sdev,
@@ -386,99 +443,215 @@ static int clariion_check_sense(struct scsi_device *sdev,
 		break;
 		break;
 	}
 	}
 
 
-	/* success just means we do not care what scsi-ml does */
-	return SUCCESS;
+	return SCSI_RETURN_NOT_HANDLED;
+}
+
+static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
+{
+	struct clariion_dh_data *h = get_clariion_data(sdev);
+	int ret = BLKPREP_OK;
+
+	if (h->lun_state != CLARIION_LUN_OWNED) {
+		ret = BLKPREP_KILL;
+		req->cmd_flags |= REQ_QUIET;
+	}
+	return ret;
+
+}
+
+static int clariion_std_inquiry(struct scsi_device *sdev,
+				struct clariion_dh_data *csdev)
+{
+	int err;
+	char *sp_model;
+
+	err = send_inquiry_cmd(sdev, 0, csdev);
+	if (err != SCSI_DH_OK && csdev->senselen) {
+		struct scsi_sense_hdr sshdr;
+
+		if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
+					 &sshdr)) {
+			sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
+				    "%02x/%02x/%02x\n", CLARIION_NAME,
+				    sshdr.sense_key, sshdr.asc, sshdr.ascq);
+		}
+		err = SCSI_DH_IO;
+		goto out;
+	}
+
+	sp_model = parse_sp_model(sdev, csdev->buffer);
+	if (!sp_model) {
+		err = SCSI_DH_DEV_UNSUPP;
+		goto out;
+	}
+
+	/*
+	 * FC Series arrays do not support long trespass
+	 */
+	if (!strlen(sp_model) || !strncmp(sp_model, "FC",2))
+		csdev->flags |= CLARIION_SHORT_TRESPASS;
+
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: detected Clariion %s, flags %x\n",
+		    CLARIION_NAME, sp_model, csdev->flags);
+out:
+	return err;
 }
 }
 
 
-static const struct {
-	char *vendor;
-	char *model;
-} clariion_dev_list[] = {
+static int clariion_send_inquiry(struct scsi_device *sdev,
+				 struct clariion_dh_data *csdev)
+{
+	int err, retry = CLARIION_RETRIES;
+
+retry:
+	err = send_inquiry_cmd(sdev, 0xC0, csdev);
+	if (err != SCSI_DH_OK && csdev->senselen) {
+		struct scsi_sense_hdr sshdr;
+
+		err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
+					   &sshdr);
+		if (!err)
+			return SCSI_DH_IO;
+
+		err = clariion_check_sense(sdev, &sshdr);
+		if (retry > 0 && err == NEEDS_RETRY) {
+			retry--;
+			goto retry;
+		}
+		sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
+			    "%02x/%02x/%02x\n", CLARIION_NAME,
+			      sshdr.sense_key, sshdr.asc, sshdr.ascq);
+		err = SCSI_DH_IO;
+	} else {
+		err = parse_sp_info_reply(sdev, csdev);
+	}
+	return err;
+}
+
+static int clariion_activate(struct scsi_device *sdev)
+{
+	struct clariion_dh_data *csdev = get_clariion_data(sdev);
+	int result;
+
+	result = clariion_send_inquiry(sdev, csdev);
+	if (result != SCSI_DH_OK)
+		goto done;
+
+	if (csdev->lun_state == CLARIION_LUN_OWNED)
+		goto done;
+
+	result = send_trespass_cmd(sdev, csdev);
+	if (result != SCSI_DH_OK)
+		goto done;
+	sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n",
+		    CLARIION_NAME,
+		    csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" );
+
+	/* Update status */
+	result = clariion_send_inquiry(sdev, csdev);
+	if (result != SCSI_DH_OK)
+		goto done;
+
+done:
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: at SP %c Port %d (%s, default SP %c)\n",
+		    CLARIION_NAME, csdev->current_sp + 'A',
+		    csdev->port, lun_state[csdev->lun_state],
+		    csdev->default_sp + 'A');
+
+	return result;
+}
+
+const struct scsi_dh_devlist clariion_dev_list[] = {
 	{"DGC", "RAID"},
 	{"DGC", "RAID"},
 	{"DGC", "DISK"},
 	{"DGC", "DISK"},
+	{"DGC", "VRAID"},
 	{NULL, NULL},
 	{NULL, NULL},
 };
 };
 
 
-static int clariion_bus_notify(struct notifier_block *, unsigned long, void *);
+static int clariion_bus_attach(struct scsi_device *sdev);
+static void clariion_bus_detach(struct scsi_device *sdev);
 
 
 static struct scsi_device_handler clariion_dh = {
 static struct scsi_device_handler clariion_dh = {
 	.name		= CLARIION_NAME,
 	.name		= CLARIION_NAME,
 	.module		= THIS_MODULE,
 	.module		= THIS_MODULE,
-	.nb.notifier_call = clariion_bus_notify,
+	.devlist	= clariion_dev_list,
+	.attach		= clariion_bus_attach,
+	.detach		= clariion_bus_detach,
 	.check_sense	= clariion_check_sense,
 	.check_sense	= clariion_check_sense,
 	.activate	= clariion_activate,
 	.activate	= clariion_activate,
+	.prep_fn	= clariion_prep_fn,
 };
 };
 
 
 /*
 /*
  * TODO: need some interface so we can set trespass values
  * TODO: need some interface so we can set trespass values
  */
  */
-static int clariion_bus_notify(struct notifier_block *nb,
-				unsigned long action, void *data)
+static int clariion_bus_attach(struct scsi_device *sdev)
 {
 {
-	struct device *dev = data;
-	struct scsi_device *sdev;
 	struct scsi_dh_data *scsi_dh_data;
 	struct scsi_dh_data *scsi_dh_data;
 	struct clariion_dh_data *h;
 	struct clariion_dh_data *h;
-	int i, found = 0;
 	unsigned long flags;
 	unsigned long flags;
+	int err;
 
 
-	if (!scsi_is_sdev_device(dev))
-		return 0;
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(*h) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
+			    CLARIION_NAME);
+		return -ENOMEM;
+	}
 
 
-	sdev = to_scsi_device(dev);
+	scsi_dh_data->scsi_dh = &clariion_dh;
+	h = (struct clariion_dh_data *) scsi_dh_data->buf;
+	h->lun_state = CLARIION_LUN_UNINITIALIZED;
+	h->default_sp = CLARIION_UNBOUND_LU;
+	h->current_sp = CLARIION_UNBOUND_LU;
 
 
-	if (action == BUS_NOTIFY_ADD_DEVICE) {
-		for (i = 0; clariion_dev_list[i].vendor; i++) {
-			if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
-				     strlen(clariion_dev_list[i].vendor)) &&
-			    !strncmp(sdev->model, clariion_dev_list[i].model,
-				     strlen(clariion_dev_list[i].model))) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			goto out;
-
-		scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
-				+ sizeof(*h) , GFP_KERNEL);
-		if (!scsi_dh_data) {
-			sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
-				    CLARIION_NAME);
-			goto out;
-		}
+	err = clariion_std_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
 
 
-		scsi_dh_data->scsi_dh = &clariion_dh;
-		h = (struct clariion_dh_data *) scsi_dh_data->buf;
-		h->default_sp = CLARIION_UNBOUND_LU;
-		h->current_sp = CLARIION_UNBOUND_LU;
+	err = clariion_send_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
 
 
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		sdev->scsi_dh_data = scsi_dh_data;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME);
-		try_module_get(THIS_MODULE);
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 
 
-	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
-		if (sdev->scsi_dh_data == NULL ||
-				sdev->scsi_dh_data->scsi_dh != &clariion_dh)
-			goto out;
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: connected to SP %c Port %d (%s, default SP %c)\n",
+		    CLARIION_NAME, h->current_sp + 'A',
+		    h->port, lun_state[h->lun_state],
+		    h->default_sp + 'A');
 
 
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		scsi_dh_data = sdev->scsi_dh_data;
-		sdev->scsi_dh_data = NULL;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+	return 0;
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n",
-			    CLARIION_NAME);
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
+		    CLARIION_NAME);
+	return -EINVAL;
+}
 
 
-		kfree(scsi_dh_data);
-		module_put(THIS_MODULE);
-	}
+static void clariion_bus_detach(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data;
+	unsigned long flags;
 
 
-out:
-	return 0;
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n",
+		    CLARIION_NAME);
+
+	kfree(scsi_dh_data);
+	module_put(THIS_MODULE);
 }
 }
 
 
 static int __init clariion_init(void)
 static int __init clariion_init(void)
@@ -487,7 +660,8 @@ static int __init clariion_init(void)
 
 
 	r = scsi_register_device_handler(&clariion_dh);
 	r = scsi_register_device_handler(&clariion_dh);
 	if (r != 0)
 	if (r != 0)
-		printk(KERN_ERR "Failed to register scsi device handler.");
+		printk(KERN_ERR "%s: Failed to register scsi device handler.",
+			CLARIION_NAME);
 	return r;
 	return r;
 }
 }
 
 

+ 261 - 87
drivers/scsi/device_handler/scsi_dh_hp_sw.c

@@ -4,6 +4,7 @@
  *
  *
  * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
  * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
  * Copyright (C) 2006 Mike Christie
  * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -25,13 +26,18 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_dh.h>
 
 
-#define HP_SW_NAME	"hp_sw"
+#define HP_SW_NAME			"hp_sw"
 
 
-#define HP_SW_TIMEOUT (60 * HZ)
-#define HP_SW_RETRIES 3
+#define HP_SW_TIMEOUT			(60 * HZ)
+#define HP_SW_RETRIES			3
+
+#define HP_SW_PATH_UNINITIALIZED	-1
+#define HP_SW_PATH_ACTIVE		0
+#define HP_SW_PATH_PASSIVE		1
 
 
 struct hp_sw_dh_data {
 struct hp_sw_dh_data {
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+	int path_state;
 	int retries;
 	int retries;
 };
 };
 
 
@@ -42,51 +48,161 @@ static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
 	return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
 	return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
 }
 }
 
 
-static int hp_sw_done(struct scsi_device *sdev)
+/*
+ * tur_done - Handle TEST UNIT READY return status
+ * @sdev: sdev the command has been sent to
+ * @errors: blk error code
+ *
+ * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
+ */
+static int tur_done(struct scsi_device *sdev, unsigned char *sense)
 {
 {
-	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
-	int rc;
-
-	sdev_printk(KERN_INFO, sdev, "hp_sw_done\n");
+	int ret;
 
 
-	rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
-	if (!rc)
+	ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
+	if (!ret) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: sending tur failed, no sense available\n",
+			    HP_SW_NAME);
+		ret = SCSI_DH_IO;
 		goto done;
 		goto done;
+	}
 	switch (sshdr.sense_key) {
 	switch (sshdr.sense_key) {
+	case UNIT_ATTENTION:
+		ret = SCSI_DH_IMM_RETRY;
+		break;
 	case NOT_READY:
 	case NOT_READY:
-		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
-			rc = SCSI_DH_RETRY;
-			h->retries++;
+		if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) {
+			/*
+			 * LUN not ready - Initialization command required
+			 *
+			 * This is the passive path
+			 */
+			ret = SCSI_DH_DEV_OFFLINED;
 			break;
 			break;
 		}
 		}
-		/* fall through */
+		/* Fallthrough */
 	default:
 	default:
-		h->retries++;
-		rc = SCSI_DH_IMM_RETRY;
+		sdev_printk(KERN_WARNING, sdev,
+			   "%s: sending tur failed, sense %x/%x/%x\n",
+			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
+			   sshdr.ascq);
+		break;
 	}
 	}
 
 
 done:
 done:
-	if (rc == SCSI_DH_OK || rc == SCSI_DH_IO)
-		h->retries = 0;
-	else if (h->retries > HP_SW_RETRIES) {
-		h->retries = 0;
+	return ret;
+}
+
+/*
+ * hp_sw_tur - Send TEST UNIT READY
+ * @sdev: sdev command should be sent to
+ *
+ * Use the TEST UNIT READY command to determine
+ * the path state.
+ */
+static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
+{
+	struct request *req;
+	int ret;
+
+	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
+	if (!req)
+		return SCSI_DH_RES_TEMP_UNAVAIL;
+
+	req->cmd_type = REQ_TYPE_BLOCK_PC;
+	req->cmd_flags |= REQ_FAILFAST;
+	req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
+	memset(req->cmd, 0, MAX_COMMAND_SIZE);
+	req->cmd[0] = TEST_UNIT_READY;
+	req->timeout = HP_SW_TIMEOUT;
+	req->sense = h->sense;
+	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	req->sense_len = 0;
+
+retry:
+	ret = blk_execute_rq(req->q, NULL, req, 1);
+	if (ret == -EIO) {
+		if (req->sense_len > 0) {
+			ret = tur_done(sdev, h->sense);
+		} else {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: sending tur failed with %x\n",
+				    HP_SW_NAME, req->errors);
+			ret = SCSI_DH_IO;
+		}
+	} else {
+		h->path_state = HP_SW_PATH_ACTIVE;
+		ret = SCSI_DH_OK;
+	}
+	if (ret == SCSI_DH_IMM_RETRY)
+		goto retry;
+	if (ret == SCSI_DH_DEV_OFFLINED) {
+		h->path_state = HP_SW_PATH_PASSIVE;
+		ret = SCSI_DH_OK;
+	}
+
+	blk_put_request(req);
+
+	return ret;
+}
+
+/*
+ * start_done - Handle START STOP UNIT return status
+ * @sdev: sdev the command has been sent to
+ * @errors: blk error code
+ */
+static int start_done(struct scsi_device *sdev, unsigned char *sense)
+{
+	struct scsi_sense_hdr sshdr;
+	int rc;
+
+	rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
+	if (!rc) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: sending start_stop_unit failed, "
+			    "no sense available\n",
+			    HP_SW_NAME);
+		return SCSI_DH_IO;
+	}
+	switch (sshdr.sense_key) {
+	case NOT_READY:
+		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
+			/*
+			 * LUN not ready - manual intervention required
+			 *
+			 * Switch-over in progress, retry.
+			 */
+			rc = SCSI_DH_RETRY;
+			break;
+		}
+		/* fall through */
+	default:
+		sdev_printk(KERN_WARNING, sdev,
+			   "%s: sending start_stop_unit failed, sense %x/%x/%x\n",
+			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
+			   sshdr.ascq);
 		rc = SCSI_DH_IO;
 		rc = SCSI_DH_IO;
 	}
 	}
+
 	return rc;
 	return rc;
 }
 }
 
 
-static int hp_sw_activate(struct scsi_device *sdev)
+/*
+ * hp_sw_start_stop - Send START STOP UNIT command
+ * @sdev: sdev command should be sent to
+ *
+ * Sending START STOP UNIT activates the SP.
+ */
+static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h)
 {
 {
-	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
 	struct request *req;
 	struct request *req;
-	int ret = SCSI_DH_RES_TEMP_UNAVAIL;
+	int ret, retry;
 
 
-	req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
+	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
 	if (!req)
 	if (!req)
-		goto done;
-
-	sdev_printk(KERN_INFO, sdev, "sending START_STOP.");
+		return SCSI_DH_RES_TEMP_UNAVAIL;
 
 
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
 	req->cmd_flags |= REQ_FAILFAST;
 	req->cmd_flags |= REQ_FAILFAST;
@@ -98,95 +214,153 @@ static int hp_sw_activate(struct scsi_device *sdev)
 	req->sense = h->sense;
 	req->sense = h->sense;
 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
 	req->sense_len = 0;
 	req->sense_len = 0;
+	retry = h->retries;
 
 
+retry:
 	ret = blk_execute_rq(req->q, NULL, req, 1);
 	ret = blk_execute_rq(req->q, NULL, req, 1);
-	if (!ret) /* SUCCESS */
-		ret = hp_sw_done(sdev);
-	else
+	if (ret == -EIO) {
+		if (req->sense_len > 0) {
+			ret = start_done(sdev, h->sense);
+		} else {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: sending start_stop_unit failed with %x\n",
+				    HP_SW_NAME, req->errors);
+			ret = SCSI_DH_IO;
+		}
+	} else
+		ret = SCSI_DH_OK;
+
+	if (ret == SCSI_DH_RETRY) {
+		if (--retry)
+			goto retry;
 		ret = SCSI_DH_IO;
 		ret = SCSI_DH_IO;
-done:
+	}
+
+	blk_put_request(req);
+
+	return ret;
+}
+
+static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
+{
+	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+	int ret = BLKPREP_OK;
+
+	if (h->path_state != HP_SW_PATH_ACTIVE) {
+		ret = BLKPREP_KILL;
+		req->cmd_flags |= REQ_QUIET;
+	}
+	return ret;
+
+}
+
+/*
+ * hp_sw_activate - Activate a path
+ * @sdev: sdev on the path to be activated
+ *
+ * The HP Active/Passive firmware is pretty simple;
+ * the passive path reports NOT READY with sense codes
+ * 0x04/0x02; a START STOP UNIT command will then
+ * activate the passive path (and deactivate the
+ * previously active one).
+ */
+static int hp_sw_activate(struct scsi_device *sdev)
+{
+	int ret = SCSI_DH_OK;
+	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+
+	ret = hp_sw_tur(sdev, h);
+
+	if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
+		ret = hp_sw_start_stop(sdev, h);
+		if (ret == SCSI_DH_OK)
+			sdev_printk(KERN_INFO, sdev,
+				    "%s: activated path\n",
+				    HP_SW_NAME);
+	}
+
 	return ret;
 	return ret;
 }
 }
 
 
-static const struct {
-	char *vendor;
-	char *model;
-} hp_sw_dh_data_list[] = {
-	{"COMPAQ", "MSA"},
-	{"HP", "HSV"},
+const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
+	{"COMPAQ", "MSA1000 VOLUME"},
+	{"COMPAQ", "HSV110"},
+	{"HP", "HSV100"},
 	{"DEC", "HSG80"},
 	{"DEC", "HSG80"},
 	{NULL, NULL},
 	{NULL, NULL},
 };
 };
 
 
-static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *);
+static int hp_sw_bus_attach(struct scsi_device *sdev);
+static void hp_sw_bus_detach(struct scsi_device *sdev);
 
 
 static struct scsi_device_handler hp_sw_dh = {
 static struct scsi_device_handler hp_sw_dh = {
 	.name		= HP_SW_NAME,
 	.name		= HP_SW_NAME,
 	.module		= THIS_MODULE,
 	.module		= THIS_MODULE,
-	.nb.notifier_call = hp_sw_bus_notify,
+	.devlist	= hp_sw_dh_data_list,
+	.attach		= hp_sw_bus_attach,
+	.detach		= hp_sw_bus_detach,
 	.activate	= hp_sw_activate,
 	.activate	= hp_sw_activate,
+	.prep_fn	= hp_sw_prep_fn,
 };
 };
 
 
-static int hp_sw_bus_notify(struct notifier_block *nb,
-			    unsigned long action, void *data)
+static int hp_sw_bus_attach(struct scsi_device *sdev)
 {
 {
-	struct device *dev = data;
-	struct scsi_device *sdev;
 	struct scsi_dh_data *scsi_dh_data;
 	struct scsi_dh_data *scsi_dh_data;
-	int i, found = 0;
+	struct hp_sw_dh_data *h;
 	unsigned long flags;
 	unsigned long flags;
+	int ret;
 
 
-	if (!scsi_is_sdev_device(dev))
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
+			    HP_SW_NAME);
 		return 0;
 		return 0;
+	}
 
 
-	sdev = to_scsi_device(dev);
-
-	if (action == BUS_NOTIFY_ADD_DEVICE) {
-		for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
-			if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
-				     strlen(hp_sw_dh_data_list[i].vendor)) &&
-			    !strncmp(sdev->model, hp_sw_dh_data_list[i].model,
-				     strlen(hp_sw_dh_data_list[i].model))) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			goto out;
+	scsi_dh_data->scsi_dh = &hp_sw_dh;
+	h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
+	h->path_state = HP_SW_PATH_UNINITIALIZED;
+	h->retries = HP_SW_RETRIES;
 
 
-		scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
-				+ sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
-		if (!scsi_dh_data) {
-			sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
-				    HP_SW_NAME);
-			goto out;
-		}
+	ret = hp_sw_tur(sdev, h);
+	if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
+		goto failed;
 
 
-		scsi_dh_data->scsi_dh = &hp_sw_dh;
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		sdev->scsi_dh_data = scsi_dh_data;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-		try_module_get(THIS_MODULE);
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
-	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
-		if (sdev->scsi_dh_data == NULL ||
-				sdev->scsi_dh_data->scsi_dh != &hp_sw_dh)
-			goto out;
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 
 
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		scsi_dh_data = sdev->scsi_dh_data;
-		sdev->scsi_dh_data = NULL;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-		module_put(THIS_MODULE);
+	sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
+		    HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
+		    "active":"passive");
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME);
+	return 0;
 
 
-		kfree(scsi_dh_data);
-	}
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
+		    HP_SW_NAME);
+	return -EINVAL;
+}
 
 
-out:
-	return 0;
+static void hp_sw_bus_detach( struct scsi_device *sdev )
+{
+	struct scsi_dh_data *scsi_dh_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+	module_put(THIS_MODULE);
+
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME);
+
+	kfree(scsi_dh_data);
 }
 }
 
 
 static int __init hp_sw_init(void)
 static int __init hp_sw_init(void)
@@ -202,6 +376,6 @@ static void __exit hp_sw_exit(void)
 module_init(hp_sw_init);
 module_init(hp_sw_init);
 module_exit(hp_sw_exit);
 module_exit(hp_sw_exit);
 
 
-MODULE_DESCRIPTION("HP MSA 1000");
+MODULE_DESCRIPTION("HP Active/Passive driver");
 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 132 - 130
drivers/scsi/device_handler/scsi_dh_rdac.c

@@ -173,6 +173,11 @@ struct rdac_dh_data {
 #define RDAC_STATE_ACTIVE	0
 #define RDAC_STATE_ACTIVE	0
 #define RDAC_STATE_PASSIVE	1
 #define RDAC_STATE_PASSIVE	1
 	unsigned char		state;
 	unsigned char		state;
+
+#define RDAC_LUN_UNOWNED	0
+#define RDAC_LUN_OWNED		1
+#define RDAC_LUN_AVT		2
+	char			lun_state;
 	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
 	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
 	union			{
 	union			{
 		struct c2_inquiry c2;
 		struct c2_inquiry c2;
@@ -182,6 +187,13 @@ struct rdac_dh_data {
 	} inq;
 	} inq;
 };
 };
 
 
+static const char *lun_state[] =
+{
+	"unowned",
+	"owned",
+	"owned (AVT mode)",
+};
+
 static LIST_HEAD(ctlr_list);
 static LIST_HEAD(ctlr_list);
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(list_lock);
 
 
@@ -197,9 +209,8 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct request_queue *q = sdev->request_queue;
 	struct request_queue *q = sdev->request_queue;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	rq = blk_get_request(q, rw, GFP_KERNEL);
+	rq = blk_get_request(q, rw, GFP_NOIO);
 
 
 	if (!rq) {
 	if (!rq) {
 		sdev_printk(KERN_INFO, sdev,
 		sdev_printk(KERN_INFO, sdev,
@@ -207,17 +218,14 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) {
+	if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
 		blk_put_request(rq);
 		blk_put_request(rq);
 		sdev_printk(KERN_INFO, sdev,
 		sdev_printk(KERN_INFO, sdev,
 				"get_rdac_req: blk_rq_map_kern failed.\n");
 				"get_rdac_req: blk_rq_map_kern failed.\n");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	memset(&rq->cmd, 0, BLK_MAX_CDB);
-	rq->sense = h->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = 0;
+	memset(rq->cmd, 0, BLK_MAX_CDB);
 
 
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
 	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
 	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
@@ -227,12 +235,12 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
 	return rq;
 	return rq;
 }
 }
 
 
-static struct request *rdac_failover_get(struct scsi_device *sdev)
+static struct request *rdac_failover_get(struct scsi_device *sdev,
+					 struct rdac_dh_data *h)
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct rdac_mode_common *common;
 	struct rdac_mode_common *common;
 	unsigned data_size;
 	unsigned data_size;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
 	if (h->ctlr->use_ms10) {
 	if (h->ctlr->use_ms10) {
 		struct rdac_pg_expanded *rdac_pg;
 		struct rdac_pg_expanded *rdac_pg;
@@ -277,6 +285,10 @@ static struct request *rdac_failover_get(struct scsi_device *sdev)
 	}
 	}
 	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 
 
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = 0;
+
 	return rq;
 	return rq;
 }
 }
 
 
@@ -321,11 +333,10 @@ done:
 }
 }
 
 
 static int submit_inquiry(struct scsi_device *sdev, int page_code,
 static int submit_inquiry(struct scsi_device *sdev, int page_code,
-		unsigned int len)
+			  unsigned int len, struct rdac_dh_data *h)
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct request_queue *q = sdev->request_queue;
 	struct request_queue *q = sdev->request_queue;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 
 
 	rq = get_rdac_req(sdev, &h->inq, len, READ);
 	rq = get_rdac_req(sdev, &h->inq, len, READ);
@@ -338,59 +349,68 @@ static int submit_inquiry(struct scsi_device *sdev, int page_code,
 	rq->cmd[2] = page_code;
 	rq->cmd[2] = page_code;
 	rq->cmd[4] = len;
 	rq->cmd[4] = len;
 	rq->cmd_len = COMMAND_SIZE(INQUIRY);
 	rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = 0;
+
 	err = blk_execute_rq(q, NULL, rq, 1);
 	err = blk_execute_rq(q, NULL, rq, 1);
 	if (err == -EIO)
 	if (err == -EIO)
 		err = SCSI_DH_IO;
 		err = SCSI_DH_IO;
+
+	blk_put_request(rq);
 done:
 done:
 	return err;
 	return err;
 }
 }
 
 
-static int get_lun(struct scsi_device *sdev)
+static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c8_inquiry *inqp;
 	struct c8_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry));
+	err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
 		inqp = &h->inq.c8;
 		inqp = &h->inq.c8;
-		h->lun = inqp->lun[7]; /* currently it uses only one byte */
+		if (inqp->page_code != 0xc8)
+			return SCSI_DH_NOSYS;
+		if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' ||
+		    inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd')
+			return SCSI_DH_NOSYS;
+		h->lun = scsilun_to_int((struct scsi_lun *)inqp->lun);
 	}
 	}
 	return err;
 	return err;
 }
 }
 
 
-#define RDAC_OWNED	0
-#define RDAC_UNOWNED	1
-#define RDAC_FAILED	2
-static int check_ownership(struct scsi_device *sdev)
+static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c9_inquiry *inqp;
 	struct c9_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry));
+	err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
-		err = RDAC_UNOWNED;
 		inqp = &h->inq.c9;
 		inqp = &h->inq.c9;
-		/*
-		 * If in AVT mode or if the path already owns the LUN,
-		 * return RDAC_OWNED;
-		 */
-		if (((inqp->avte_cvp >> 7) == 0x1) ||
-				 ((inqp->avte_cvp & 0x1) != 0))
-			err = RDAC_OWNED;
-	} else
-		err = RDAC_FAILED;
+		if ((inqp->avte_cvp >> 7) == 0x1) {
+			/* LUN in AVT mode */
+			sdev_printk(KERN_NOTICE, sdev,
+				    "%s: AVT mode detected\n",
+				    RDAC_NAME);
+			h->lun_state = RDAC_LUN_AVT;
+		} else if ((inqp->avte_cvp & 0x1) != 0) {
+			/* LUN was owned by the controller */
+			h->lun_state = RDAC_LUN_OWNED;
+		}
+	}
+
 	return err;
 	return err;
 }
 }
 
 
-static int initialize_controller(struct scsi_device *sdev)
+static int initialize_controller(struct scsi_device *sdev,
+				 struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c4_inquiry *inqp;
 	struct c4_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry));
+	err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
 		inqp = &h->inq.c4;
 		inqp = &h->inq.c4;
 		h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
 		h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
@@ -400,13 +420,12 @@ static int initialize_controller(struct scsi_device *sdev)
 	return err;
 	return err;
 }
 }
 
 
-static int set_mode_select(struct scsi_device *sdev)
+static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c2_inquiry *inqp;
 	struct c2_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry));
+	err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
 		inqp = &h->inq.c2;
 		inqp = &h->inq.c2;
 		/*
 		/*
@@ -421,13 +440,13 @@ static int set_mode_select(struct scsi_device *sdev)
 	return err;
 	return err;
 }
 }
 
 
-static int mode_select_handle_sense(struct scsi_device *sdev)
+static int mode_select_handle_sense(struct scsi_device *sdev,
+				    unsigned char *sensebuf)
 {
 {
 	struct scsi_sense_hdr sense_hdr;
 	struct scsi_sense_hdr sense_hdr;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int sense, err = SCSI_DH_IO, ret;
 	int sense, err = SCSI_DH_IO, ret;
 
 
-	ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
+	ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
 	if (!ret)
 	if (!ret)
 		goto done;
 		goto done;
 
 
@@ -451,14 +470,13 @@ done:
 	return err;
 	return err;
 }
 }
 
 
-static int send_mode_select(struct scsi_device *sdev)
+static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct request_queue *q = sdev->request_queue;
 	struct request_queue *q = sdev->request_queue;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 
 
-	rq = rdac_failover_get(sdev);
+	rq = rdac_failover_get(sdev, h);
 	if (!rq)
 	if (!rq)
 		goto done;
 		goto done;
 
 
@@ -466,9 +484,11 @@ static int send_mode_select(struct scsi_device *sdev)
 
 
 	err = blk_execute_rq(q, NULL, rq, 1);
 	err = blk_execute_rq(q, NULL, rq, 1);
 	if (err != SCSI_DH_OK)
 	if (err != SCSI_DH_OK)
-		err = mode_select_handle_sense(sdev);
+		err = mode_select_handle_sense(sdev, h->sense);
 	if (err == SCSI_DH_OK)
 	if (err == SCSI_DH_OK)
 		h->state = RDAC_STATE_ACTIVE;
 		h->state = RDAC_STATE_ACTIVE;
+
+	blk_put_request(rq);
 done:
 done:
 	return err;
 	return err;
 }
 }
@@ -478,38 +498,23 @@ static int rdac_activate(struct scsi_device *sdev)
 	struct rdac_dh_data *h = get_rdac_data(sdev);
 	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int err = SCSI_DH_OK;
 	int err = SCSI_DH_OK;
 
 
-	if (h->lun == UNINITIALIZED_LUN) {
-		err = get_lun(sdev);
-		if (err != SCSI_DH_OK)
-			goto done;
-	}
-
-	err = check_ownership(sdev);
-	switch (err) {
-	case RDAC_UNOWNED:
-		break;
-	case RDAC_OWNED:
-		err = SCSI_DH_OK;
-		goto done;
-	case RDAC_FAILED:
-	default:
-		err = SCSI_DH_IO;
+	err = check_ownership(sdev, h);
+	if (err != SCSI_DH_OK)
 		goto done;
 		goto done;
-	}
 
 
 	if (!h->ctlr) {
 	if (!h->ctlr) {
-		err = initialize_controller(sdev);
+		err = initialize_controller(sdev, h);
 		if (err != SCSI_DH_OK)
 		if (err != SCSI_DH_OK)
 			goto done;
 			goto done;
 	}
 	}
 
 
 	if (h->ctlr->use_ms10 == -1) {
 	if (h->ctlr->use_ms10 == -1) {
-		err = set_mode_select(sdev);
+		err = set_mode_select(sdev, h);
 		if (err != SCSI_DH_OK)
 		if (err != SCSI_DH_OK)
 			goto done;
 			goto done;
 	}
 	}
-
-	err = send_mode_select(sdev);
+	if (h->lun_state == RDAC_LUN_UNOWNED)
+		err = send_mode_select(sdev, h);
 done:
 done:
 	return err;
 	return err;
 }
 }
@@ -569,10 +574,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
 	return SCSI_RETURN_NOT_HANDLED;
 	return SCSI_RETURN_NOT_HANDLED;
 }
 }
 
 
-static const struct {
-	char *vendor;
-	char *model;
-} rdac_dev_list[] = {
+const struct scsi_dh_devlist rdac_dev_list[] = {
 	{"IBM", "1722"},
 	{"IBM", "1722"},
 	{"IBM", "1724"},
 	{"IBM", "1724"},
 	{"IBM", "1726"},
 	{"IBM", "1726"},
@@ -590,89 +592,89 @@ static const struct {
 	{NULL, NULL},
 	{NULL, NULL},
 };
 };
 
 
-static int rdac_bus_notify(struct notifier_block *, unsigned long, void *);
+static int rdac_bus_attach(struct scsi_device *sdev);
+static void rdac_bus_detach(struct scsi_device *sdev);
 
 
 static struct scsi_device_handler rdac_dh = {
 static struct scsi_device_handler rdac_dh = {
 	.name = RDAC_NAME,
 	.name = RDAC_NAME,
 	.module = THIS_MODULE,
 	.module = THIS_MODULE,
-	.nb.notifier_call = rdac_bus_notify,
+	.devlist = rdac_dev_list,
 	.prep_fn = rdac_prep_fn,
 	.prep_fn = rdac_prep_fn,
 	.check_sense = rdac_check_sense,
 	.check_sense = rdac_check_sense,
+	.attach = rdac_bus_attach,
+	.detach = rdac_bus_detach,
 	.activate = rdac_activate,
 	.activate = rdac_activate,
 };
 };
 
 
-/*
- * TODO: need some interface so we can set trespass values
- */
-static int rdac_bus_notify(struct notifier_block *nb,
-			    unsigned long action, void *data)
+static int rdac_bus_attach(struct scsi_device *sdev)
 {
 {
-	struct device *dev = data;
-	struct scsi_device *sdev;
 	struct scsi_dh_data *scsi_dh_data;
 	struct scsi_dh_data *scsi_dh_data;
 	struct rdac_dh_data *h;
 	struct rdac_dh_data *h;
-	int i, found = 0;
 	unsigned long flags;
 	unsigned long flags;
+	int err;
 
 
-	if (!scsi_is_sdev_device(dev))
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(*h) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
+			    RDAC_NAME);
 		return 0;
 		return 0;
+	}
 
 
-	sdev = to_scsi_device(dev);
-
-	if (action == BUS_NOTIFY_ADD_DEVICE) {
-		for (i = 0; rdac_dev_list[i].vendor; i++) {
-			if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
-				     strlen(rdac_dev_list[i].vendor)) &&
-			    !strncmp(sdev->model, rdac_dev_list[i].model,
-				     strlen(rdac_dev_list[i].model))) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			goto out;
+	scsi_dh_data->scsi_dh = &rdac_dh;
+	h = (struct rdac_dh_data *) scsi_dh_data->buf;
+	h->lun = UNINITIALIZED_LUN;
+	h->state = RDAC_STATE_ACTIVE;
 
 
-		scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
-				+ sizeof(*h) , GFP_KERNEL);
-		if (!scsi_dh_data) {
-			sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
-				    RDAC_NAME);
-			goto out;
-		}
+	err = get_lun(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
 
 
-		scsi_dh_data->scsi_dh = &rdac_dh;
-		h = (struct rdac_dh_data *) scsi_dh_data->buf;
-		h->lun = UNINITIALIZED_LUN;
-		h->state = RDAC_STATE_ACTIVE;
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		sdev->scsi_dh_data = scsi_dh_data;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-		try_module_get(THIS_MODULE);
-
-		sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME);
-
-	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
-		if (sdev->scsi_dh_data == NULL ||
-				sdev->scsi_dh_data->scsi_dh != &rdac_dh)
-			goto out;
-
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		scsi_dh_data = sdev->scsi_dh_data;
-		sdev->scsi_dh_data = NULL;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-
-		h = (struct rdac_dh_data *) scsi_dh_data->buf;
-		if (h->ctlr)
-			kref_put(&h->ctlr->kref, release_controller);
-		kfree(scsi_dh_data);
-		module_put(THIS_MODULE);
-		sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME);
-	}
+	err = check_ownership(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
+
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	sdev_printk(KERN_NOTICE, sdev,
+		    "%s: LUN %d (%s)\n",
+		    RDAC_NAME, h->lun, lun_state[(int)h->lun_state]);
 
 
-out:
 	return 0;
 	return 0;
+
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
+		    RDAC_NAME);
+	return -EINVAL;
+}
+
+static void rdac_bus_detach( struct scsi_device *sdev )
+{
+	struct scsi_dh_data *scsi_dh_data;
+	struct rdac_dh_data *h;
+	unsigned long flags;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	h = (struct rdac_dh_data *) scsi_dh_data->buf;
+	if (h->ctlr)
+		kref_put(&h->ctlr->kref, release_controller);
+	kfree(scsi_dh_data);
+	module_put(THIS_MODULE);
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME);
 }
 }
 
 
+
+
 static int __init rdac_init(void)
 static int __init rdac_init(void)
 {
 {
 	int r;
 	int r;

+ 177 - 27
drivers/scsi/ibmvscsi/ibmvfc.c

@@ -521,9 +521,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
 static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
 static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
 {
 {
 	if (vhost->action == IBMVFC_HOST_ACTION_NONE) {
 	if (vhost->action == IBMVFC_HOST_ACTION_NONE) {
-		scsi_block_requests(vhost->host);
-		ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING);
-		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+		if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
+			scsi_block_requests(vhost->host);
+			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+		}
 	} else
 	} else
 		vhost->reinit = 1;
 		vhost->reinit = 1;
 
 
@@ -854,39 +855,41 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
 }
 }
 
 
 /**
 /**
- * __ibmvfc_find_target - Find the specified scsi_target (no locking)
+ * __ibmvfc_get_target - Find the specified scsi_target (no locking)
  * @starget:	scsi target struct
  * @starget:	scsi target struct
  *
  *
  * Return value:
  * Return value:
  *	ibmvfc_target struct / NULL if not found
  *	ibmvfc_target struct / NULL if not found
  **/
  **/
-static struct ibmvfc_target *__ibmvfc_find_target(struct scsi_target *starget)
+static struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget)
 {
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct ibmvfc_host *vhost = shost_priv(shost);
 	struct ibmvfc_host *vhost = shost_priv(shost);
 	struct ibmvfc_target *tgt;
 	struct ibmvfc_target *tgt;
 
 
 	list_for_each_entry(tgt, &vhost->targets, queue)
 	list_for_each_entry(tgt, &vhost->targets, queue)
-		if (tgt->target_id == starget->id)
+		if (tgt->target_id == starget->id) {
+			kref_get(&tgt->kref);
 			return tgt;
 			return tgt;
+		}
 	return NULL;
 	return NULL;
 }
 }
 
 
 /**
 /**
- * ibmvfc_find_target - Find the specified scsi_target
+ * ibmvfc_get_target - Find the specified scsi_target
  * @starget:	scsi target struct
  * @starget:	scsi target struct
  *
  *
  * Return value:
  * Return value:
  *	ibmvfc_target struct / NULL if not found
  *	ibmvfc_target struct / NULL if not found
  **/
  **/
-static struct ibmvfc_target *ibmvfc_find_target(struct scsi_target *starget)
+static struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget)
 {
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct ibmvfc_target *tgt;
 	struct ibmvfc_target *tgt;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(shost->host_lock, flags);
 	spin_lock_irqsave(shost->host_lock, flags);
-	tgt = __ibmvfc_find_target(starget);
+	tgt = __ibmvfc_get_target(starget);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	return tgt;
 	return tgt;
 }
 }
@@ -963,6 +966,9 @@ static void ibmvfc_get_host_port_state(struct Scsi_Host *shost)
 	case IBMVFC_HALTED:
 	case IBMVFC_HALTED:
 		fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED;
 		fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED;
 		break;
 		break;
+	case IBMVFC_NO_CRQ:
+		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+		break;
 	default:
 	default:
 		ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state);
 		ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state);
 		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
 		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
@@ -987,6 +993,17 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
 		rport->dev_loss_tmo = 1;
 		rport->dev_loss_tmo = 1;
 }
 }
 
 
+/**
+ * ibmvfc_release_tgt - Free memory allocated for a target
+ * @kref:		kref struct
+ *
+ **/
+static void ibmvfc_release_tgt(struct kref *kref)
+{
+	struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
+	kfree(tgt);
+}
+
 /**
 /**
  * ibmvfc_get_starget_node_name - Get SCSI target's node name
  * ibmvfc_get_starget_node_name - Get SCSI target's node name
  * @starget:	scsi target struct
  * @starget:	scsi target struct
@@ -996,8 +1013,10 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
  **/
  **/
 static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
 static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
 {
 {
-	struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
+	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
 	fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0;
 	fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0;
+	if (tgt)
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
 }
 }
 
 
 /**
 /**
@@ -1009,8 +1028,10 @@ static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
  **/
  **/
 static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
 static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
 {
 {
-	struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
+	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
 	fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0;
 	fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0;
+	if (tgt)
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
 }
 }
 
 
 /**
 /**
@@ -1022,8 +1043,10 @@ static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
  **/
  **/
 static void ibmvfc_get_starget_port_id(struct scsi_target *starget)
 static void ibmvfc_get_starget_port_id(struct scsi_target *starget)
 {
 {
-	struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
+	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
 	fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1;
 	fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1;
+	if (tgt)
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
 }
 }
 
 
 /**
 /**
@@ -1113,7 +1136,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
 	login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
 	login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
 	login_info->capabilities = IBMVFC_CAN_MIGRATE;
 	login_info->capabilities = IBMVFC_CAN_MIGRATE;
 	login_info->async.va = vhost->async_crq.msg_token;
 	login_info->async.va = vhost->async_crq.msg_token;
-	login_info->async.len = vhost->async_crq.size;
+	login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs);
 	strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
 	strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
 	strncpy(login_info->device_name,
 	strncpy(login_info->device_name,
 		vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
 		vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
@@ -1404,7 +1427,7 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)
 		err = cmd_status[index].name;
 		err = cmd_status[index].name;
 	}
 	}
 
 
-	if (!logerr && (vhost->log_level <= IBMVFC_DEFAULT_LOG_LEVEL))
+	if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1)))
 		return;
 		return;
 
 
 	if (rsp->flags & FCP_RSP_LEN_VALID)
 	if (rsp->flags & FCP_RSP_LEN_VALID)
@@ -2054,7 +2077,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
 {
 {
 	const char *desc = ibmvfc_get_ae_desc(crq->event);
 	const char *desc = ibmvfc_get_ae_desc(crq->event);
 
 
-	ibmvfc_log(vhost, 2, "%s event received\n", desc);
+	ibmvfc_log(vhost, 3, "%s event received\n", desc);
 
 
 	switch (crq->event) {
 	switch (crq->event) {
 	case IBMVFC_AE_LINK_UP:
 	case IBMVFC_AE_LINK_UP:
@@ -2647,17 +2670,6 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
 		ibmvfc_init_tgt(tgt, job_step);
 		ibmvfc_init_tgt(tgt, job_step);
 }
 }
 
 
-/**
- * ibmvfc_release_tgt - Free memory allocated for a target
- * @kref:		kref struct
- *
- **/
-static void ibmvfc_release_tgt(struct kref *kref)
-{
-	struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
-	kfree(tgt);
-}
-
 /**
 /**
  * ibmvfc_tgt_prli_done - Completion handler for Process Login
  * ibmvfc_tgt_prli_done - Completion handler for Process Login
  * @evt:	ibmvfc event struct
  * @evt:	ibmvfc event struct
@@ -2901,6 +2913,139 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
 		tgt_dbg(tgt, "Sent Implicit Logout\n");
 		tgt_dbg(tgt, "Sent Implicit Logout\n");
 }
 }
 
 
+/**
+ * ibmvfc_adisc_needs_plogi - Does device need PLOGI?
+ * @mad:	ibmvfc passthru mad struct
+ * @tgt:	ibmvfc target struct
+ *
+ * Returns:
+ *	1 if PLOGI needed / 0 if PLOGI not needed
+ **/
+static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad,
+				    struct ibmvfc_target *tgt)
+{
+	if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name,
+		   sizeof(tgt->ids.port_name)))
+		return 1;
+	if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name,
+		   sizeof(tgt->ids.node_name)))
+		return 1;
+	if (mad->fc_iu.response[6] != tgt->scsi_id)
+		return 1;
+	return 0;
+}
+
+/**
+ * ibmvfc_tgt_adisc_done - Completion handler for ADISC
+ * @evt:	ibmvfc event struct
+ *
+ **/
+static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)
+{
+	struct ibmvfc_target *tgt = evt->tgt;
+	struct ibmvfc_host *vhost = evt->vhost;
+	struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
+	u32 status = mad->common.status;
+	u8 fc_reason, fc_explain;
+
+	vhost->discovery_threads--;
+	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
+
+	switch (status) {
+	case IBMVFC_MAD_SUCCESS:
+		tgt_dbg(tgt, "ADISC succeeded\n");
+		if (ibmvfc_adisc_needs_plogi(mad, tgt))
+			tgt->need_login = 1;
+		break;
+	case IBMVFC_MAD_DRIVER_FAILED:
+		break;
+	case IBMVFC_MAD_FAILED:
+	default:
+		tgt->need_login = 1;
+		fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16;
+		fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8;
+		tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
+			 ibmvfc_get_cmd_error(mad->iu.status, mad->iu.error),
+			 mad->iu.status, mad->iu.error,
+			 ibmvfc_get_fc_type(fc_reason), fc_reason,
+			 ibmvfc_get_ls_explain(fc_explain), fc_explain, status);
+		break;
+	};
+
+	kref_put(&tgt->kref, ibmvfc_release_tgt);
+	ibmvfc_free_event(evt);
+	wake_up(&vhost->work_wait_q);
+}
+
+/**
+ * ibmvfc_init_passthru - Initialize an event struct for FC passthru
+ * @evt:		ibmvfc event struct
+ *
+ **/
+static void ibmvfc_init_passthru(struct ibmvfc_event *evt)
+{
+	struct ibmvfc_passthru_mad *mad = &evt->iu.passthru;
+
+	memset(mad, 0, sizeof(*mad));
+	mad->common.version = 1;
+	mad->common.opcode = IBMVFC_PASSTHRU;
+	mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu);
+	mad->cmd_ioba.va = (u64)evt->crq.ioba +
+		offsetof(struct ibmvfc_passthru_mad, iu);
+	mad->cmd_ioba.len = sizeof(mad->iu);
+	mad->iu.cmd_len = sizeof(mad->fc_iu.payload);
+	mad->iu.rsp_len = sizeof(mad->fc_iu.response);
+	mad->iu.cmd.va = (u64)evt->crq.ioba +
+		offsetof(struct ibmvfc_passthru_mad, fc_iu) +
+		offsetof(struct ibmvfc_passthru_fc_iu, payload);
+	mad->iu.cmd.len = sizeof(mad->fc_iu.payload);
+	mad->iu.rsp.va = (u64)evt->crq.ioba +
+		offsetof(struct ibmvfc_passthru_mad, fc_iu) +
+		offsetof(struct ibmvfc_passthru_fc_iu, response);
+	mad->iu.rsp.len = sizeof(mad->fc_iu.response);
+}
+
+/**
+ * ibmvfc_tgt_adisc - Initiate an ADISC for specified target
+ * @tgt:		ibmvfc target struct
+ *
+ **/
+static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt)
+{
+	struct ibmvfc_passthru_mad *mad;
+	struct ibmvfc_host *vhost = tgt->vhost;
+	struct ibmvfc_event *evt;
+
+	if (vhost->discovery_threads >= disc_threads)
+		return;
+
+	kref_get(&tgt->kref);
+	evt = ibmvfc_get_event(vhost);
+	vhost->discovery_threads++;
+	ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT);
+	evt->tgt = tgt;
+
+	ibmvfc_init_passthru(evt);
+	mad = &evt->iu.passthru;
+	mad->iu.flags = IBMVFC_FC_ELS;
+	mad->iu.scsi_id = tgt->scsi_id;
+
+	mad->fc_iu.payload[0] = IBMVFC_ADISC;
+	memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name,
+	       sizeof(vhost->login_buf->resp.port_name));
+	memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name,
+	       sizeof(vhost->login_buf->resp.node_name));
+	mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff;
+
+	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
+	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
+		vhost->discovery_threads--;
+		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
+	} else
+		tgt_dbg(tgt, "Sent ADISC\n");
+}
+
 /**
 /**
  * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD
  * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD
  * @evt:	ibmvfc event struct
  * @evt:	ibmvfc event struct
@@ -2921,6 +3066,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
 		tgt->new_scsi_id = rsp->scsi_id;
 		tgt->new_scsi_id = rsp->scsi_id;
 		if (rsp->scsi_id != tgt->scsi_id)
 		if (rsp->scsi_id != tgt->scsi_id)
 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
+		else
+			ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc);
 		break;
 		break;
 	case IBMVFC_MAD_DRIVER_FAILED:
 	case IBMVFC_MAD_DRIVER_FAILED:
 		break;
 		break;
@@ -3336,6 +3483,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
 		tgt_dbg(tgt, "rport add succeeded\n");
 		tgt_dbg(tgt, "rport add succeeded\n");
 		rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
 		rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
 		rport->supported_classes = 0;
 		rport->supported_classes = 0;
+		tgt->target_id = rport->scsi_target_id;
 		if (tgt->service_parms.class1_parms[0] & 0x80000000)
 		if (tgt->service_parms.class1_parms[0] & 0x80000000)
 			rport->supported_classes |= FC_COS_CLASS1;
 			rport->supported_classes |= FC_COS_CLASS1;
 		if (tgt->service_parms.class2_parms[0] & 0x80000000)
 		if (tgt->service_parms.class2_parms[0] & 0x80000000)
@@ -3800,10 +3948,12 @@ static int ibmvfc_remove(struct vio_dev *vdev)
 
 
 	ENTER;
 	ENTER;
 	ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
 	ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
+	ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
+	ibmvfc_wait_while_resetting(vhost);
+	ibmvfc_release_crq_queue(vhost);
 	kthread_stop(vhost->work_thread);
 	kthread_stop(vhost->work_thread);
 	fc_remove_host(vhost->host);
 	fc_remove_host(vhost->host);
 	scsi_remove_host(vhost->host);
 	scsi_remove_host(vhost->host);
-	ibmvfc_release_crq_queue(vhost);
 
 
 	spin_lock_irqsave(vhost->host->host_lock, flags);
 	spin_lock_irqsave(vhost->host->host_lock, flags);
 	ibmvfc_purge_requests(vhost, DID_ERROR);
 	ibmvfc_purge_requests(vhost, DID_ERROR);

+ 40 - 4
drivers/scsi/ibmvscsi/ibmvfc.h

@@ -29,8 +29,8 @@
 #include "viosrp.h"
 #include "viosrp.h"
 
 
 #define IBMVFC_NAME	"ibmvfc"
 #define IBMVFC_NAME	"ibmvfc"
-#define IBMVFC_DRIVER_VERSION		"1.0.0"
-#define IBMVFC_DRIVER_DATE		"(July 1, 2008)"
+#define IBMVFC_DRIVER_VERSION		"1.0.1"
+#define IBMVFC_DRIVER_DATE		"(July 11, 2008)"
 
 
 #define IBMVFC_DEFAULT_TIMEOUT	15
 #define IBMVFC_DEFAULT_TIMEOUT	15
 #define IBMVFC_INIT_TIMEOUT		30
 #define IBMVFC_INIT_TIMEOUT		30
@@ -119,6 +119,7 @@ enum ibmvfc_mad_types {
 	IBMVFC_PROCESS_LOGIN	= 0x0008,
 	IBMVFC_PROCESS_LOGIN	= 0x0008,
 	IBMVFC_QUERY_TARGET	= 0x0010,
 	IBMVFC_QUERY_TARGET	= 0x0010,
 	IBMVFC_IMPLICIT_LOGOUT	= 0x0040,
 	IBMVFC_IMPLICIT_LOGOUT	= 0x0040,
+	IBMVFC_PASSTHRU		= 0x0200,
 	IBMVFC_TMF_MAD		= 0x0100,
 	IBMVFC_TMF_MAD		= 0x0100,
 };
 };
 
 
@@ -439,6 +440,37 @@ struct ibmvfc_cmd {
 	struct ibmvfc_fcp_rsp rsp;
 	struct ibmvfc_fcp_rsp rsp;
 }__attribute__((packed, aligned (8)));
 }__attribute__((packed, aligned (8)));
 
 
+struct ibmvfc_passthru_fc_iu {
+	u32 payload[7];
+#define IBMVFC_ADISC	0x52000000
+	u32 response[7];
+};
+
+struct ibmvfc_passthru_iu {
+	u64 task_tag;
+	u32 cmd_len;
+	u32 rsp_len;
+	u16 status;
+	u16 error;
+	u32 flags;
+#define IBMVFC_FC_ELS		0x01
+	u32 cancel_key;
+	u32 reserved;
+	struct srp_direct_buf cmd;
+	struct srp_direct_buf rsp;
+	u64 correlation;
+	u64 scsi_id;
+	u64 tag;
+	u64 reserved2[2];
+}__attribute__((packed, aligned (8)));
+
+struct ibmvfc_passthru_mad {
+	struct ibmvfc_mad_common common;
+	struct srp_direct_buf cmd_ioba;
+	struct ibmvfc_passthru_iu iu;
+	struct ibmvfc_passthru_fc_iu fc_iu;
+}__attribute__((packed, aligned (8)));
+
 struct ibmvfc_trace_start_entry {
 struct ibmvfc_trace_start_entry {
 	u32 xfer_len;
 	u32 xfer_len;
 }__attribute__((packed));
 }__attribute__((packed));
@@ -531,6 +563,7 @@ union ibmvfc_iu {
 	struct ibmvfc_implicit_logout implicit_logout;
 	struct ibmvfc_implicit_logout implicit_logout;
 	struct ibmvfc_tmf tmf;
 	struct ibmvfc_tmf tmf;
 	struct ibmvfc_cmd cmd;
 	struct ibmvfc_cmd cmd;
+	struct ibmvfc_passthru_mad passthru;
 }__attribute__((packed, aligned (8)));
 }__attribute__((packed, aligned (8)));
 
 
 enum ibmvfc_target_action {
 enum ibmvfc_target_action {
@@ -656,6 +689,9 @@ struct ibmvfc_host {
 #define tgt_dbg(t, fmt, ...)			\
 #define tgt_dbg(t, fmt, ...)			\
 	DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__))
 	DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__))
 
 
+#define tgt_info(t, fmt, ...)		\
+	dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
+
 #define tgt_err(t, fmt, ...)		\
 #define tgt_err(t, fmt, ...)		\
 	dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
 	dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
 
 
@@ -668,8 +704,8 @@ struct ibmvfc_host {
 			dev_err((vhost)->dev, ##__VA_ARGS__); \
 			dev_err((vhost)->dev, ##__VA_ARGS__); \
 	} while (0)
 	} while (0)
 
 
-#define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __FUNCTION__))
-#define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __FUNCTION__))
+#define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __func__))
+#define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __func__))
 
 
 #ifdef CONFIG_SCSI_IBMVFC_TRACE
 #ifdef CONFIG_SCSI_IBMVFC_TRACE
 #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr)
 #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr)

+ 1 - 1
drivers/scsi/ibmvscsi/ibmvstgt.c

@@ -55,7 +55,7 @@
 /* tmp - will replace with SCSI logging stuff */
 /* tmp - will replace with SCSI logging stuff */
 #define eprintk(fmt, args...)					\
 #define eprintk(fmt, args...)					\
 do {								\
 do {								\
-	printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);	\
+	printk("%s(%d) " fmt, __func__, __LINE__, ##args);	\
 } while (0)
 } while (0)
 /* #define dprintk eprintk */
 /* #define dprintk eprintk */
 #define dprintk(fmt, args...)
 #define dprintk(fmt, args...)

+ 1 - 1
drivers/scsi/imm.c

@@ -163,7 +163,7 @@ static int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start,
 
 
 #if IMM_DEBUG > 0
 #if IMM_DEBUG > 0
 #define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
 #define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
-	   y, __FUNCTION__, __LINE__); imm_fail_func(x,y);
+	   y, __func__, __LINE__); imm_fail_func(x,y);
 static inline void
 static inline void
 imm_fail_func(imm_struct *dev, int error_code)
 imm_fail_func(imm_struct *dev, int error_code)
 #else
 #else

+ 3 - 3
drivers/scsi/ipr.h

@@ -1403,10 +1403,10 @@ struct ipr_ucode_image_header {
 }
 }
 
 
 #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
 #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
-	__FILE__, __FUNCTION__, __LINE__)
+	__FILE__, __func__, __LINE__)
 
 
-#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__))
-#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__))
+#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __func__))
+#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __func__))
 
 
 #define ipr_err_separator \
 #define ipr_err_separator \
 ipr_err("----------------------------------------------------------\n")
 ipr_err("----------------------------------------------------------\n")

+ 8 - 8
drivers/scsi/libsas/sas_ata.c

@@ -74,7 +74,7 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
 		case SAS_OPEN_TO:
 		case SAS_OPEN_TO:
 		case SAS_OPEN_REJECT:
 		case SAS_OPEN_REJECT:
 			SAS_DPRINTK("%s: Saw error %d.  What to do?\n",
 			SAS_DPRINTK("%s: Saw error %d.  What to do?\n",
-				    __FUNCTION__, ts->stat);
+				    __func__, ts->stat);
 			return AC_ERR_OTHER;
 			return AC_ERR_OTHER;
 
 
 		case SAS_ABORTED_TASK:
 		case SAS_ABORTED_TASK:
@@ -115,7 +115,7 @@ static void sas_ata_task_done(struct sas_task *task)
 	} else if (stat->stat != SAM_STAT_GOOD) {
 	} else if (stat->stat != SAM_STAT_GOOD) {
 		ac = sas_to_ata_err(stat);
 		ac = sas_to_ata_err(stat);
 		if (ac) {
 		if (ac) {
-			SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__,
+			SAS_DPRINTK("%s: SAS error %x\n", __func__,
 				    stat->stat);
 				    stat->stat);
 			/* We saw a SAS error. Send a vague error. */
 			/* We saw a SAS error. Send a vague error. */
 			qc->err_mask = ac;
 			qc->err_mask = ac;
@@ -244,20 +244,20 @@ static void sas_ata_phy_reset(struct ata_port *ap)
 		res = i->dft->lldd_I_T_nexus_reset(dev);
 		res = i->dft->lldd_I_T_nexus_reset(dev);
 
 
 	if (res != TMF_RESP_FUNC_COMPLETE)
 	if (res != TMF_RESP_FUNC_COMPLETE)
-		SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
+		SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__);
 
 
 	switch (dev->sata_dev.command_set) {
 	switch (dev->sata_dev.command_set) {
 		case ATA_COMMAND_SET:
 		case ATA_COMMAND_SET:
-			SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
+			SAS_DPRINTK("%s: Found ATA device.\n", __func__);
 			ap->link.device[0].class = ATA_DEV_ATA;
 			ap->link.device[0].class = ATA_DEV_ATA;
 			break;
 			break;
 		case ATAPI_COMMAND_SET:
 		case ATAPI_COMMAND_SET:
-			SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
+			SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
 			ap->link.device[0].class = ATA_DEV_ATAPI;
 			ap->link.device[0].class = ATA_DEV_ATAPI;
 			break;
 			break;
 		default:
 		default:
 			SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
 			SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
-				    __FUNCTION__,
+				    __func__,
 				    dev->sata_dev.command_set);
 				    dev->sata_dev.command_set);
 			ap->link.device[0].class = ATA_DEV_UNKNOWN;
 			ap->link.device[0].class = ATA_DEV_UNKNOWN;
 			break;
 			break;
@@ -299,7 +299,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
 {
 {
 	struct domain_device *dev = ap->private_data;
 	struct domain_device *dev = ap->private_data;
 
 
-	SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+	SAS_DPRINTK("STUB %s\n", __func__);
 	switch (sc_reg_in) {
 	switch (sc_reg_in) {
 		case SCR_STATUS:
 		case SCR_STATUS:
 			dev->sata_dev.sstatus = val;
 			dev->sata_dev.sstatus = val;
@@ -324,7 +324,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
 {
 {
 	struct domain_device *dev = ap->private_data;
 	struct domain_device *dev = ap->private_data;
 
 
-	SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+	SAS_DPRINTK("STUB %s\n", __func__);
 	switch (sc_reg_in) {
 	switch (sc_reg_in) {
 		case SCR_STATUS:
 		case SCR_STATUS:
 			*val = dev->sata_dev.sstatus;
 			*val = dev->sata_dev.sstatus;

+ 6 - 6
drivers/scsi/libsas/sas_expander.c

@@ -121,7 +121,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 			break;
 			break;
 		} else {
 		} else {
 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
-				    "status 0x%x\n", __FUNCTION__,
+				    "status 0x%x\n", __func__,
 				    SAS_ADDR(dev->sas_addr),
 				    SAS_ADDR(dev->sas_addr),
 				    task->task_status.resp,
 				    task->task_status.resp,
 				    task->task_status.stat);
 				    task->task_status.stat);
@@ -1279,7 +1279,7 @@ static int sas_configure_present(struct domain_device *dev, int phy_id,
 			goto out;
 			goto out;
 		} else if (res != SMP_RESP_FUNC_ACC) {
 		} else if (res != SMP_RESP_FUNC_ACC) {
 			SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
 			SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
-				    "result 0x%x\n", __FUNCTION__,
+				    "result 0x%x\n", __func__,
 				    SAS_ADDR(dev->sas_addr), phy_id, i, res);
 				    SAS_ADDR(dev->sas_addr), phy_id, i, res);
 			goto out;
 			goto out;
 		}
 		}
@@ -1901,7 +1901,7 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
 
 	if (!rsp) {
 	if (!rsp) {
 		printk("%s: space for a smp response is missing\n",
 		printk("%s: space for a smp response is missing\n",
-		       __FUNCTION__);
+		       __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -1914,20 +1914,20 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 	if (type != SAS_EDGE_EXPANDER_DEVICE &&
 	if (type != SAS_EDGE_EXPANDER_DEVICE &&
 	    type != SAS_FANOUT_EXPANDER_DEVICE) {
 	    type != SAS_FANOUT_EXPANDER_DEVICE) {
 		printk("%s: can we send a smp request to a device?\n",
 		printk("%s: can we send a smp request to a device?\n",
-		       __FUNCTION__);
+		       __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	dev = sas_find_dev_by_rphy(rphy);
 	dev = sas_find_dev_by_rphy(rphy);
 	if (!dev) {
 	if (!dev) {
-		printk("%s: fail to find a domain_device?\n", __FUNCTION__);
+		printk("%s: fail to find a domain_device?\n", __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	/* do we need to support multiple segments? */
 	/* do we need to support multiple segments? */
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 		printk("%s: multiple segments req %u %u, rsp %u %u\n",
 		printk("%s: multiple segments req %u %u, rsp %u %u\n",
-		       __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+		       __func__, req->bio->bi_vcnt, req->data_len,
 		       rsp->bio->bi_vcnt, rsp->data_len);
 		       rsp->bio->bi_vcnt, rsp->data_len);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}

+ 2 - 2
drivers/scsi/libsas/sas_port.c

@@ -50,7 +50,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
 			sas_deform_port(phy);
 			sas_deform_port(phy);
 		else {
 		else {
 			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
 			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
-				    __FUNCTION__, phy->id, phy->port->id,
+				    __func__, phy->id, phy->port->id,
 				    phy->port->num_phys);
 				    phy->port->num_phys);
 			return;
 			return;
 		}
 		}
@@ -78,7 +78,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
 
 
 	if (i >= sas_ha->num_phys) {
 	if (i >= sas_ha->num_phys) {
 		printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
 		printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
-		       __FUNCTION__);
+		       __func__);
 		spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
 		spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
 		return;
 		return;
 	}
 	}

+ 15 - 15
drivers/scsi/libsas/sas_scsi_host.c

@@ -343,7 +343,7 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
 						       flags);
 						       flags);
 				SAS_DPRINTK("%s: task 0x%p aborted from "
 				SAS_DPRINTK("%s: task 0x%p aborted from "
 					    "task_queue\n",
 					    "task_queue\n",
-					    __FUNCTION__, task);
+					    __func__, task);
 				return TASK_IS_ABORTED;
 				return TASK_IS_ABORTED;
 			}
 			}
 		}
 		}
@@ -351,13 +351,13 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
 	}
 	}
 
 
 	for (i = 0; i < 5; i++) {
 	for (i = 0; i < 5; i++) {
-		SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
+		SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task);
 		res = si->dft->lldd_abort_task(task);
 		res = si->dft->lldd_abort_task(task);
 
 
 		spin_lock_irqsave(&task->task_state_lock, flags);
 		spin_lock_irqsave(&task->task_state_lock, flags);
 		if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 			spin_unlock_irqrestore(&task->task_state_lock, flags);
 			spin_unlock_irqrestore(&task->task_state_lock, flags);
-			SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+			SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
 				    task);
 				    task);
 			return TASK_IS_DONE;
 			return TASK_IS_DONE;
 		}
 		}
@@ -365,24 +365,24 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
 
 
 		if (res == TMF_RESP_FUNC_COMPLETE) {
 		if (res == TMF_RESP_FUNC_COMPLETE) {
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			return TASK_IS_ABORTED;
 			return TASK_IS_ABORTED;
 		} else if (si->dft->lldd_query_task) {
 		} else if (si->dft->lldd_query_task) {
 			SAS_DPRINTK("%s: querying task 0x%p\n",
 			SAS_DPRINTK("%s: querying task 0x%p\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			res = si->dft->lldd_query_task(task);
 			res = si->dft->lldd_query_task(task);
 			switch (res) {
 			switch (res) {
 			case TMF_RESP_FUNC_SUCC:
 			case TMF_RESP_FUNC_SUCC:
 				SAS_DPRINTK("%s: task 0x%p at LU\n",
 				SAS_DPRINTK("%s: task 0x%p at LU\n",
-					    __FUNCTION__, task);
+					    __func__, task);
 				return TASK_IS_AT_LU;
 				return TASK_IS_AT_LU;
 			case TMF_RESP_FUNC_COMPLETE:
 			case TMF_RESP_FUNC_COMPLETE:
 				SAS_DPRINTK("%s: task 0x%p not at LU\n",
 				SAS_DPRINTK("%s: task 0x%p not at LU\n",
-					    __FUNCTION__, task);
+					    __func__, task);
 				return TASK_IS_NOT_AT_LU;
 				return TASK_IS_NOT_AT_LU;
 			case TMF_RESP_FUNC_FAILED:
 			case TMF_RESP_FUNC_FAILED:
                                 SAS_DPRINTK("%s: task 0x%p failed to abort\n",
                                 SAS_DPRINTK("%s: task 0x%p failed to abort\n",
-                                                __FUNCTION__, task);
+                                                __func__, task);
                                 return TASK_ABORT_FAILED;
                                 return TASK_ABORT_FAILED;
                         }
                         }
 
 
@@ -545,7 +545,7 @@ Again:
 
 
 		if (need_reset) {
 		if (need_reset) {
 			SAS_DPRINTK("%s: task 0x%p requests reset\n",
 			SAS_DPRINTK("%s: task 0x%p requests reset\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			goto reset;
 			goto reset;
 		}
 		}
 
 
@@ -556,13 +556,13 @@ Again:
 
 
 		switch (res) {
 		switch (res) {
 		case TASK_IS_DONE:
 		case TASK_IS_DONE:
-			SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+			SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
 				    task);
 				    task);
 			sas_eh_finish_cmd(cmd);
 			sas_eh_finish_cmd(cmd);
 			continue;
 			continue;
 		case TASK_IS_ABORTED:
 		case TASK_IS_ABORTED:
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			sas_eh_finish_cmd(cmd);
 			sas_eh_finish_cmd(cmd);
 			continue;
 			continue;
 		case TASK_IS_AT_LU:
 		case TASK_IS_AT_LU:
@@ -633,7 +633,7 @@ Again:
 	}
 	}
 	return list_empty(work_q);
 	return list_empty(work_q);
 clear_q:
 clear_q:
-	SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
+	SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__);
 	list_for_each_entry_safe(cmd, n, work_q, eh_entry)
 	list_for_each_entry_safe(cmd, n, work_q, eh_entry)
 		sas_eh_finish_cmd(cmd);
 		sas_eh_finish_cmd(cmd);
 
 
@@ -650,7 +650,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
 	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
 	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 
-	SAS_DPRINTK("Enter %s\n", __FUNCTION__);
+	SAS_DPRINTK("Enter %s\n", __func__);
 	/*
 	/*
 	 * Deal with commands that still have SAS tasks (i.e. they didn't
 	 * Deal with commands that still have SAS tasks (i.e. they didn't
 	 * complete via the normal sas_task completion mechanism)
 	 * complete via the normal sas_task completion mechanism)
@@ -669,7 +669,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
 
 
 out:
 out:
 	scsi_eh_flush_done_q(&ha->eh_done_q);
 	scsi_eh_flush_done_q(&ha->eh_done_q);
-	SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
+	SAS_DPRINTK("--- Exit %s\n", __func__);
 	return;
 	return;
 }
 }
 
 
@@ -990,7 +990,7 @@ int __sas_task_abort(struct sas_task *task)
 	if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
 	if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
 	    task->task_state_flags & SAS_TASK_STATE_DONE) {
 	    task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__,
+		SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
 			    task);
 			    task);
 		return 0;
 		return 0;
 	}
 	}

+ 1 - 1
drivers/scsi/libsrp.c

@@ -39,7 +39,7 @@ enum srp_task_attributes {
 /* tmp - will replace with SCSI logging stuff */
 /* tmp - will replace with SCSI logging stuff */
 #define eprintk(fmt, args...)					\
 #define eprintk(fmt, args...)					\
 do {								\
 do {								\
-	printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);	\
+	printk("%s(%d) " fmt, __func__, __LINE__, ##args);	\
 } while (0)
 } while (0)
 /* #define dprintk eprintk */
 /* #define dprintk eprintk */
 #define dprintk(fmt, args...)
 #define dprintk(fmt, args...)

+ 2 - 2
drivers/scsi/lpfc/lpfc_init.c

@@ -2083,7 +2083,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 		if (iocbq_entry == NULL) {
 		if (iocbq_entry == NULL) {
 			printk(KERN_ERR "%s: only allocated %d iocbs of "
 			printk(KERN_ERR "%s: only allocated %d iocbs of "
 				"expected %d count. Unloading driver.\n",
 				"expected %d count. Unloading driver.\n",
-				__FUNCTION__, i, LPFC_IOCB_LIST_CNT);
+				__func__, i, LPFC_IOCB_LIST_CNT);
 			error = -ENOMEM;
 			error = -ENOMEM;
 			goto out_free_iocbq;
 			goto out_free_iocbq;
 		}
 		}
@@ -2093,7 +2093,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 			kfree (iocbq_entry);
 			kfree (iocbq_entry);
 			printk(KERN_ERR "%s: failed to allocate IOTAG. "
 			printk(KERN_ERR "%s: failed to allocate IOTAG. "
 			       "Unloading driver.\n",
 			       "Unloading driver.\n",
-				__FUNCTION__);
+				__func__);
 			error = -ENOMEM;
 			error = -ENOMEM;
 			goto out_free_iocbq;
 			goto out_free_iocbq;
 		}
 		}

+ 1 - 1
drivers/scsi/lpfc/lpfc_scsi.c

@@ -341,7 +341,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
 		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
 			printk(KERN_ERR "%s: Too many sg segments from "
 			printk(KERN_ERR "%s: Too many sg segments from "
 			       "dma_map_sg.  Config %d, seg_cnt %d",
 			       "dma_map_sg.  Config %d, seg_cnt %d",
-			       __FUNCTION__, phba->cfg_sg_seg_cnt,
+			       __func__, phba->cfg_sg_seg_cnt,
 			       lpfc_cmd->seg_cnt);
 			       lpfc_cmd->seg_cnt);
 			scsi_dma_unmap(scsi_cmnd);
 			scsi_dma_unmap(scsi_cmnd);
 			return 1;
 			return 1;

+ 3 - 3
drivers/scsi/lpfc/lpfc_sli.c

@@ -219,7 +219,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
 	case CMD_IOCB_LOGENTRY_CN:
 	case CMD_IOCB_LOGENTRY_CN:
 	case CMD_IOCB_LOGENTRY_ASYNC_CN:
 	case CMD_IOCB_LOGENTRY_ASYNC_CN:
 		printk("%s - Unhandled SLI-3 Command x%x\n",
 		printk("%s - Unhandled SLI-3 Command x%x\n",
-				__FUNCTION__, iocb_cmnd);
+				__func__, iocb_cmnd);
 		type = LPFC_UNKNOWN_IOCB;
 		type = LPFC_UNKNOWN_IOCB;
 		break;
 		break;
 	default:
 	default:
@@ -1715,7 +1715,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 		rspiocbp = __lpfc_sli_get_iocbq(phba);
 		rspiocbp = __lpfc_sli_get_iocbq(phba);
 		if (rspiocbp == NULL) {
 		if (rspiocbp == NULL) {
 			printk(KERN_ERR "%s: out of buffers! Failing "
 			printk(KERN_ERR "%s: out of buffers! Failing "
-			       "completion.\n", __FUNCTION__);
+			       "completion.\n", __func__);
 			break;
 			break;
 		}
 		}
 
 
@@ -3793,7 +3793,7 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
 		break;
 		break;
 	default:
 	default:
 		printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
 		printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
-			__FUNCTION__, ctx_cmd);
+			__func__, ctx_cmd);
 		break;
 		break;
 	}
 	}
 
 

+ 1 - 1
drivers/scsi/megaraid/mega_common.h

@@ -265,7 +265,7 @@ typedef struct {
 #define ASSERT(expression)						\
 #define ASSERT(expression)						\
 	if (!(expression)) {						\
 	if (!(expression)) {						\
 	ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n",	\
 	ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n",	\
-			#expression, __FILE__, __LINE__, __FUNCTION__);	\
+			#expression, __FILE__, __LINE__, __func__);	\
 	}
 	}
 #else
 #else
 #define ASSERT(expression)
 #define ASSERT(expression)

+ 8 - 8
drivers/scsi/megaraid/megaraid_mbox.c

@@ -458,7 +458,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 
 	if (adapter == NULL) {
 	if (adapter == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-		"megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__));
+		"megaraid: out of memory, %s %d.\n", __func__, __LINE__));
 
 
 		goto out_probe_one;
 		goto out_probe_one;
 	}
 	}
@@ -1002,7 +1002,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 
 
 	if (!raid_dev->una_mbox64) {
 	if (!raid_dev->una_mbox64) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		return -1;
 		return -1;
 	}
 	}
@@ -1030,7 +1030,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 	if (!adapter->ibuf) {
 	if (!adapter->ibuf) {
 
 
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		goto out_free_common_mbox;
 		goto out_free_common_mbox;
@@ -1052,7 +1052,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 
 
 	if (adapter->kscb_list == NULL) {
 	if (adapter->kscb_list == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		goto out_free_ibuf;
 		goto out_free_ibuf;
 	}
 	}
@@ -1060,7 +1060,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 	// memory allocation for our command packets
 	// memory allocation for our command packets
 	if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
 	if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		goto out_free_scb_list;
 		goto out_free_scb_list;
 	}
 	}
@@ -2981,7 +2981,7 @@ megaraid_mbox_product_info(adapter_t *adapter)
 
 
 	if (pinfo == NULL) {
 	if (pinfo == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		return -1;
 		return -1;
@@ -3508,7 +3508,7 @@ megaraid_cmm_register(adapter_t *adapter)
 
 
 	if (adapter->uscb_list == NULL) {
 	if (adapter->uscb_list == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		return -1;
 		return -1;
 	}
 	}
@@ -3879,7 +3879,7 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter)
 		!raid_dev->sysfs_buffer) {
 		!raid_dev->sysfs_buffer) {
 
 
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		rval = -ENOMEM;
 		rval = -ENOMEM;

+ 2 - 2
drivers/scsi/megaraid/megaraid_mm.c

@@ -929,7 +929,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
 			!adapter->pthru_dma_pool) {
 			!adapter->pthru_dma_pool) {
 
 
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid cmm: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid cmm: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		rval = (-ENOMEM);
 		rval = (-ENOMEM);
@@ -957,7 +957,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
 
 
 			con_log(CL_ANN, (KERN_WARNING
 			con_log(CL_ANN, (KERN_WARNING
 				"megaraid cmm: out of memory, %s %d\n",
 				"megaraid cmm: out of memory, %s %d\n",
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 
 
 			rval = (-ENOMEM);
 			rval = (-ENOMEM);
 
 

+ 2 - 2
drivers/scsi/nsp32.c

@@ -299,9 +299,9 @@ static struct scsi_host_template nsp32_template = {
 #else
 #else
 # define NSP32_DEBUG_MASK	      0xffffff
 # define NSP32_DEBUG_MASK	      0xffffff
 # define nsp32_msg(type, args...) \
 # define nsp32_msg(type, args...) \
-	nsp32_message (__FUNCTION__, __LINE__, (type), args)
+	nsp32_message (__func__, __LINE__, (type), args)
 # define nsp32_dbg(mask, args...) \
 # define nsp32_dbg(mask, args...) \
-	nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args)
+	nsp32_dmessage(__func__, __LINE__, (mask), args)
 #endif
 #endif
 
 
 #define NSP32_DEBUG_QUEUECOMMAND	BIT(0)
 #define NSP32_DEBUG_QUEUECOMMAND	BIT(0)

+ 1 - 1
drivers/scsi/nsp32_debug.c

@@ -88,7 +88,7 @@ static void print_commandk (unsigned char *command)
 	int i,s;
 	int i,s;
 //	printk(KERN_DEBUG);
 //	printk(KERN_DEBUG);
 	print_opcodek(command[0]);
 	print_opcodek(command[0]);
-	/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
+	/*printk(KERN_DEBUG "%s ", __func__);*/
 	if ((command[0] >> 5) == 6 ||
 	if ((command[0] >> 5) == 6 ||
 	    (command[0] >> 5) == 7 ) {
 	    (command[0] >> 5) == 7 ) {
 		s = 12; /* vender specific */
 		s = 12; /* vender specific */

+ 2 - 2
drivers/scsi/pcmcia/nsp_cs.c

@@ -107,9 +107,9 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
 #else
 #else
 # define NSP_DEBUG_MASK		0xffffff
 # define NSP_DEBUG_MASK		0xffffff
 # define nsp_msg(type, args...) \
 # define nsp_msg(type, args...) \
-	nsp_cs_message (__FUNCTION__, __LINE__, (type), args)
+	nsp_cs_message (__func__, __LINE__, (type), args)
 # define nsp_dbg(mask, args...) \
 # define nsp_dbg(mask, args...) \
-	nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args)
+	nsp_cs_dmessage(__func__, __LINE__, (mask), args)
 #endif
 #endif
 
 
 #define NSP_DEBUG_QUEUECOMMAND		BIT(0)
 #define NSP_DEBUG_QUEUECOMMAND		BIT(0)

+ 1 - 1
drivers/scsi/pcmcia/nsp_debug.c

@@ -90,7 +90,7 @@ static void print_commandk (unsigned char *command)
 	int i, s;
 	int i, s;
 	printk(KERN_DEBUG);
 	printk(KERN_DEBUG);
 	print_opcodek(command[0]);
 	print_opcodek(command[0]);
-	/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
+	/*printk(KERN_DEBUG "%s ", __func__);*/
 	if ((command[0] >> 5) == 6 ||
 	if ((command[0] >> 5) == 6 ||
 	    (command[0] >> 5) == 7 ) {
 	    (command[0] >> 5) == 7 ) {
 		s = 12; /* vender specific */
 		s = 12; /* vender specific */

+ 1 - 1
drivers/scsi/ppa.c

@@ -171,7 +171,7 @@ static int device_check(ppa_struct *dev);
 
 
 #if PPA_DEBUG > 0
 #if PPA_DEBUG > 0
 #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
 #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
-	   y, __FUNCTION__, __LINE__); ppa_fail_func(x,y);
+	   y, __func__, __LINE__); ppa_fail_func(x,y);
 static inline void ppa_fail_func(ppa_struct *dev, int error_code)
 static inline void ppa_fail_func(ppa_struct *dev, int error_code)
 #else
 #else
 static inline void ppa_fail(ppa_struct *dev, int error_code)
 static inline void ppa_fail(ppa_struct *dev, int error_code)

+ 6 - 6
drivers/scsi/qla1280.c

@@ -1695,7 +1695,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
 	risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
 	risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
 
 
 	dprintk(1, "%s: DMA RISC code (%i) words\n",
 	dprintk(1, "%s: DMA RISC code (%i) words\n",
-			__FUNCTION__, risc_code_size);
+			__func__, risc_code_size);
 
 
 	num = 0;
 	num = 0;
 	while (risc_code_size > 0) {
 	while (risc_code_size > 0) {
@@ -1721,7 +1721,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
 		mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
 		mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
 		mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
 		mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
 		dprintk(2, "%s: op=%d  0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",
 		dprintk(2, "%s: op=%d  0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",
-				__FUNCTION__, mb[0],
+				__func__, mb[0],
 				(void *)(long)ha->request_dma,
 				(void *)(long)ha->request_dma,
 				mb[6], mb[7], mb[2], mb[3]);
 				mb[6], mb[7], mb[2], mb[3]);
 		err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
 		err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
@@ -1753,10 +1753,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
 			if (tbuf[i] != sp[i] && warn++ < 10) {
 			if (tbuf[i] != sp[i] && warn++ < 10) {
 				printk(KERN_ERR "%s: FW compare error @ "
 				printk(KERN_ERR "%s: FW compare error @ "
 						"byte(0x%x) loop#=%x\n",
 						"byte(0x%x) loop#=%x\n",
-						__FUNCTION__, i, num);
+						__func__, i, num);
 				printk(KERN_ERR "%s: FWbyte=%x  "
 				printk(KERN_ERR "%s: FWbyte=%x  "
 						"FWfromChip=%x\n",
 						"FWfromChip=%x\n",
-						__FUNCTION__, sp[i], tbuf[i]);
+						__func__, sp[i], tbuf[i]);
 				/*break; */
 				/*break; */
 			}
 			}
 		}
 		}
@@ -1781,7 +1781,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha)
 	int err;
 	int err;
 
 
 	dprintk(1, "%s: Verifying checksum of loaded RISC code.\n",
 	dprintk(1, "%s: Verifying checksum of loaded RISC code.\n",
-			__FUNCTION__);
+			__func__);
 
 
 	/* Verify checksum of loaded RISC code. */
 	/* Verify checksum of loaded RISC code. */
 	mb[0] = MBC_VERIFY_CHECKSUM;
 	mb[0] = MBC_VERIFY_CHECKSUM;
@@ -1794,7 +1794,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha)
 	}
 	}
 
 
 	/* Start firmware execution. */
 	/* Start firmware execution. */
-	dprintk(1, "%s: start firmware running.\n", __FUNCTION__);
+	dprintk(1, "%s: start firmware running.\n", __func__);
 	mb[0] = MBC_EXECUTE_FIRMWARE;
 	mb[0] = MBC_EXECUTE_FIRMWARE;
 	mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
 	mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
 	err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
 	err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);

+ 61 - 57
drivers/scsi/qla2xxx/qla_attr.c

@@ -20,18 +20,12 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
 {
 {
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
 	    struct device, kobj)));
-	char *rbuf = (char *)ha->fw_dump;
 
 
 	if (ha->fw_dump_reading == 0)
 	if (ha->fw_dump_reading == 0)
 		return 0;
 		return 0;
-	if (off > ha->fw_dump_len)
-                return 0;
-	if (off + count > ha->fw_dump_len)
-		count = ha->fw_dump_len - off;
 
 
-	memcpy(buf, &rbuf[off], count);
-
-	return (count);
+	return memory_read_from_buffer(buf, count, &off, ha->fw_dump,
+					ha->fw_dump_len);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -94,20 +88,13 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
 {
 {
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
 	    struct device, kobj)));
-	int		size = ha->nvram_size;
-	char		*nvram_cache = ha->nvram;
 
 
-	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
+	if (!capable(CAP_SYS_ADMIN))
 		return 0;
 		return 0;
-	if (off + count > size) {
-		size -= off;
-		count = size;
-	}
 
 
 	/* Read NVRAM data from cache. */
 	/* Read NVRAM data from cache. */
-	memcpy(buf, &nvram_cache[off], count);
-
-	return count;
+	return memory_read_from_buffer(buf, count, &off, ha->nvram,
+					ha->nvram_size);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -175,14 +162,9 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj,
 
 
 	if (ha->optrom_state != QLA_SREADING)
 	if (ha->optrom_state != QLA_SREADING)
 		return 0;
 		return 0;
-	if (off > ha->optrom_region_size)
-		return 0;
-	if (off + count > ha->optrom_region_size)
-		count = ha->optrom_region_size - off;
-
-	memcpy(buf, &ha->optrom_buffer[off], count);
 
 
-	return count;
+	return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
+					ha->optrom_region_size);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -374,20 +356,12 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
 {
 {
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
 	    struct device, kobj)));
-	int           size = ha->vpd_size;
-	char          *vpd_cache = ha->vpd;
 
 
-	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
+	if (!capable(CAP_SYS_ADMIN))
 		return 0;
 		return 0;
-	if (off + count > size) {
-		size -= off;
-		count = size;
-	}
 
 
 	/* Read NVRAM data from cache. */
 	/* Read NVRAM data from cache. */
-	memcpy(buf, &vpd_cache[off], count);
-
-	return count;
+	return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -557,8 +531,10 @@ qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
 	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
 	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
 	uint32_t sn;
 	uint32_t sn;
 
 
-	if (IS_FWI2_CAPABLE(ha))
-		return snprintf(buf, PAGE_SIZE, "\n");
+	if (IS_FWI2_CAPABLE(ha)) {
+		qla2xxx_get_vpd_field(ha, "SN", buf, PAGE_SIZE);
+		return snprintf(buf, PAGE_SIZE, "%s\n", buf);
+	}
 
 
 	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
 	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
 	return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
 	return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
@@ -809,6 +785,16 @@ qla2x00_optrom_fw_version_show(struct device *dev,
 	    ha->fw_revision[3]);
 	    ha->fw_revision[3]);
 }
 }
 
 
+static ssize_t
+qla2x00_total_isp_aborts_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+	    ha->qla_stats.total_isp_aborts);
+}
+
 static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
 static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
 static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
 static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
 static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
 static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -831,6 +817,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
 		   qla2x00_optrom_fcode_version_show, NULL);
 		   qla2x00_optrom_fcode_version_show, NULL);
 static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
 static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
 		   NULL);
 		   NULL);
+static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
+		   NULL);
 
 
 struct device_attribute *qla2x00_host_attrs[] = {
 struct device_attribute *qla2x00_host_attrs[] = {
 	&dev_attr_driver_version,
 	&dev_attr_driver_version,
@@ -849,6 +837,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
 	&dev_attr_optrom_efi_version,
 	&dev_attr_optrom_efi_version,
 	&dev_attr_optrom_fcode_version,
 	&dev_attr_optrom_fcode_version,
 	&dev_attr_optrom_fw_version,
 	&dev_attr_optrom_fw_version,
+	&dev_attr_total_isp_aborts,
 	NULL,
 	NULL,
 };
 };
 
 
@@ -972,26 +961,39 @@ qla2x00_get_starget_port_id(struct scsi_target *starget)
 }
 }
 
 
 static void
 static void
-qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
+qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
 {
 {
-	struct Scsi_Host *host = rport_to_shost(rport);
-	scsi_qla_host_t *ha = shost_priv(host);
-
-	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+	if (timeout)
+		rport->dev_loss_tmo = timeout;
+	else
+		rport->dev_loss_tmo = 1;
 }
 }
 
 
 static void
 static void
-qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
 {
 {
 	struct Scsi_Host *host = rport_to_shost(rport);
 	struct Scsi_Host *host = rport_to_shost(rport);
-	scsi_qla_host_t *ha = shost_priv(host);
+	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
+
+	qla2x00_abort_fcport_cmds(fcport);
+
+	/*
+	 * Transport has effectively 'deleted' the rport, clear
+	 * all local references.
+	 */
+	spin_lock_irq(host->host_lock);
+	fcport->rport = NULL;
+	*((fc_port_t **)rport->dd_data) = NULL;
+	spin_unlock_irq(host->host_lock);
+}
 
 
-	if (timeout)
-		ha->port_down_retry_count = timeout;
-	else
-		ha->port_down_retry_count = 1;
+static void
+qla2x00_terminate_rport_io(struct fc_rport *rport)
+{
+	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
 
 
-	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+	qla2x00_abort_fcport_cmds(fcport);
+	scsi_target_unblock(&rport->dev);
 }
 }
 
 
 static int
 static int
@@ -1045,6 +1047,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
 	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
 	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
 	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
 	if (IS_FWI2_CAPABLE(ha)) {
 	if (IS_FWI2_CAPABLE(ha)) {
+		pfc_host_stat->lip_count = stats->lip_cnt;
 		pfc_host_stat->tx_frames = stats->tx_frames;
 		pfc_host_stat->tx_frames = stats->tx_frames;
 		pfc_host_stat->rx_frames = stats->rx_frames;
 		pfc_host_stat->rx_frames = stats->rx_frames;
 		pfc_host_stat->dumped_frames = stats->dumped_frames;
 		pfc_host_stat->dumped_frames = stats->dumped_frames;
@@ -1173,17 +1176,16 @@ vport_create_failed_2:
 static int
 static int
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 {
 {
-	scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
 	scsi_qla_host_t *vha = fc_vport->dd_data;
 	scsi_qla_host_t *vha = fc_vport->dd_data;
+	scsi_qla_host_t *pha = to_qla_parent(vha);
+
+	while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) ||
+	    test_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags))
+		msleep(1000);
 
 
 	qla24xx_disable_vp(vha);
 	qla24xx_disable_vp(vha);
 	qla24xx_deallocate_vp_id(vha);
 	qla24xx_deallocate_vp_id(vha);
 
 
-	mutex_lock(&ha->vport_lock);
-	ha->cur_vport_count--;
-	clear_bit(vha->vp_idx, ha->vp_idx_map);
-	mutex_unlock(&ha->vport_lock);
-
 	kfree(vha->node_name);
 	kfree(vha->node_name);
 	kfree(vha->port_name);
 	kfree(vha->port_name);
 
 
@@ -1248,11 +1250,12 @@ struct fc_function_template qla2xxx_transport_functions = {
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.show_starget_port_id = 1,
 	.show_starget_port_id = 1,
 
 
-	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.show_rport_dev_loss_tmo = 1,
 	.show_rport_dev_loss_tmo = 1,
 
 
 	.issue_fc_host_lip = qla2x00_issue_lip,
 	.issue_fc_host_lip = qla2x00_issue_lip,
+	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
+	.terminate_rport_io = qla2x00_terminate_rport_io,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 
 
 	.vport_create = qla24xx_vport_create,
 	.vport_create = qla24xx_vport_create,
@@ -1291,11 +1294,12 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.show_starget_port_id = 1,
 	.show_starget_port_id = 1,
 
 
-	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.show_rport_dev_loss_tmo = 1,
 	.show_rport_dev_loss_tmo = 1,
 
 
 	.issue_fc_host_lip = qla2x00_issue_lip,
 	.issue_fc_host_lip = qla2x00_issue_lip,
+	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
+	.terminate_rport_io = qla2x00_terminate_rport_io,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 };
 };
 
 

+ 1 - 1
drivers/scsi/qla2xxx/qla_dbg.c

@@ -216,7 +216,7 @@ qla24xx_soft_reset(scsi_qla_host_t *ha)
 
 
 static int
 static int
 qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram,
 qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram,
-    uint16_t ram_words, void **nxt)
+    uint32_t ram_words, void **nxt)
 {
 {
 	int rval;
 	int rval;
 	uint32_t cnt, stat, timer, words, idx;
 	uint32_t cnt, stat, timer, words, idx;

+ 8 - 4
drivers/scsi/qla2xxx/qla_def.h

@@ -864,7 +864,8 @@ struct link_statistics {
 	uint32_t prim_seq_err_cnt;
 	uint32_t prim_seq_err_cnt;
 	uint32_t inval_xmit_word_cnt;
 	uint32_t inval_xmit_word_cnt;
 	uint32_t inval_crc_cnt;
 	uint32_t inval_crc_cnt;
-	uint32_t unused1[0x1b];
+	uint32_t lip_cnt;
+	uint32_t unused1[0x1a];
 	uint32_t tx_frames;
 	uint32_t tx_frames;
 	uint32_t rx_frames;
 	uint32_t rx_frames;
 	uint32_t dumped_frames;
 	uint32_t dumped_frames;
@@ -1544,7 +1545,6 @@ typedef struct fc_port {
 	int login_retry;
 	int login_retry;
 	atomic_t port_down_timer;
 	atomic_t port_down_timer;
 
 
-	spinlock_t rport_lock;
 	struct fc_rport *rport, *drport;
 	struct fc_rport *rport, *drport;
 	u32 supported_classes;
 	u32 supported_classes;
 
 
@@ -2155,6 +2155,10 @@ struct qla_chip_state_84xx {
 	uint32_t gold_fw_version;
 	uint32_t gold_fw_version;
 };
 };
 
 
+struct qla_statistics {
+	uint32_t total_isp_aborts;
+};
+
 /*
 /*
  * Linux Host Adapter structure
  * Linux Host Adapter structure
  */
  */
@@ -2166,7 +2170,6 @@ typedef struct scsi_qla_host {
 	struct pci_dev	*pdev;
 	struct pci_dev	*pdev;
 
 
 	unsigned long	host_no;
 	unsigned long	host_no;
-	unsigned long	instance;
 
 
 	volatile struct {
 	volatile struct {
 		uint32_t	init_done		:1;
 		uint32_t	init_done		:1;
@@ -2515,7 +2518,7 @@ typedef struct scsi_qla_host {
 
 
 	uint8_t		model_number[16+1];
 	uint8_t		model_number[16+1];
 #define BINZERO		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 #define BINZERO		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-	char		*model_desc;
+	char		model_desc[80];
 	uint8_t		adapter_id[16+1];
 	uint8_t		adapter_id[16+1];
 
 
 	uint8_t		*node_name;
 	uint8_t		*node_name;
@@ -2596,6 +2599,7 @@ typedef struct scsi_qla_host {
 	int		cur_vport_count;
 	int		cur_vport_count;
 
 
 	struct qla_chip_state_84xx *cs84xx;
 	struct qla_chip_state_84xx *cs84xx;
+	struct qla_statistics qla_stats;
 } scsi_qla_host_t;
 } scsi_qla_host_t;
 
 
 
 

+ 4 - 1
drivers/scsi/qla2xxx/qla_gbl.h

@@ -62,7 +62,7 @@ extern int ql2xfdmienable;
 extern int ql2xallocfwdump;
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
 extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
 extern int ql2xqfullrampup;
-extern int num_hosts;
+extern int ql2xiidmaenable;
 
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -71,6 +71,8 @@ extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
 extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t,
 extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t,
     uint16_t, uint16_t);
     uint16_t, uint16_t);
 
 
+extern void qla2x00_abort_fcport_cmds(fc_port_t *);
+
 /*
 /*
  * Global Functions in qla_mid.c source file.
  * Global Functions in qla_mid.c source file.
  */
  */
@@ -312,6 +314,7 @@ extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t,
     uint16_t, uint16_t);
     uint16_t, uint16_t);
 
 
 extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
 extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
+extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
 
 
 /*
 /*
  * Global Function Prototypes in qla_dbg.c source file.
  * Global Function Prototypes in qla_dbg.c source file.

+ 6 - 0
drivers/scsi/qla2xxx/qla_gs.c

@@ -1661,6 +1661,12 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha)
 {
 {
 	int rval;
 	int rval;
 
 
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		DEBUG2(printk("scsi(%ld): FDMI unsupported on "
+		    "ISP2100/ISP2200.\n", ha->host_no));
+		return QLA_SUCCESS;
+	}
+
 	rval = qla2x00_mgmt_svr_login(ha);
 	rval = qla2x00_mgmt_svr_login(ha);
 	if (rval)
 	if (rval)
 		return rval;
 		return rval;

+ 73 - 60
drivers/scsi/qla2xxx/qla_init.c

@@ -334,6 +334,8 @@ static int
 qla2x00_isp_firmware(scsi_qla_host_t *ha)
 qla2x00_isp_firmware(scsi_qla_host_t *ha)
 {
 {
 	int  rval;
 	int  rval;
+	uint16_t loop_id, topo, sw_cap;
+	uint8_t domain, area, al_pa;
 
 
 	/* Assume loading risc code */
 	/* Assume loading risc code */
 	rval = QLA_FUNCTION_FAILED;
 	rval = QLA_FUNCTION_FAILED;
@@ -345,6 +347,11 @@ qla2x00_isp_firmware(scsi_qla_host_t *ha)
 
 
 		/* Verify checksum of loaded RISC code. */
 		/* Verify checksum of loaded RISC code. */
 		rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
 		rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
+		if (rval == QLA_SUCCESS) {
+			/* And, verify we are not in ROM code. */
+			rval = qla2x00_get_adapter_id(ha, &loop_id, &al_pa,
+			    &area, &domain, &topo, &sw_cap);
+		}
 	}
 	}
 
 
 	if (rval) {
 	if (rval) {
@@ -722,7 +729,7 @@ qla24xx_chip_diag(scsi_qla_host_t *ha)
 	/* Perform RISC reset. */
 	/* Perform RISC reset. */
 	qla24xx_reset_risc(ha);
 	qla24xx_reset_risc(ha);
 
 
-	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
+	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->request_q_length;
 
 
 	rval = qla2x00_mbx_reg_test(ha);
 	rval = qla2x00_mbx_reg_test(ha);
 	if (rval) {
 	if (rval) {
@@ -768,42 +775,16 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
 		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
 		    sizeof(uint32_t);
 		    sizeof(uint32_t);
 
 
-		/* Allocate memory for Extended Trace Buffer. */
-		tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
-		    GFP_KERNEL);
-		if (!tc) {
-			qla_printk(KERN_WARNING, ha, "Unable to allocate "
-			    "(%d KB) for EFT.\n", EFT_SIZE / 1024);
-			goto cont_alloc;
-		}
-
-		memset(tc, 0, EFT_SIZE);
-		rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
-		if (rval) {
-			qla_printk(KERN_WARNING, ha, "Unable to initialize "
-			    "EFT (%d).\n", rval);
-			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
-			    tc_dma);
-			goto cont_alloc;
-		}
-
-		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
-		    EFT_SIZE / 1024);
-
-		eft_size = EFT_SIZE;
-		ha->eft_dma = tc_dma;
-		ha->eft = tc;
-
 		/* Allocate memory for Fibre Channel Event Buffer. */
 		/* Allocate memory for Fibre Channel Event Buffer. */
 		if (!IS_QLA25XX(ha))
 		if (!IS_QLA25XX(ha))
-			goto cont_alloc;
+			goto try_eft;
 
 
 		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
 		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
 		    GFP_KERNEL);
 		    GFP_KERNEL);
 		if (!tc) {
 		if (!tc) {
 			qla_printk(KERN_WARNING, ha, "Unable to allocate "
 			qla_printk(KERN_WARNING, ha, "Unable to allocate "
 			    "(%d KB) for FCE.\n", FCE_SIZE / 1024);
 			    "(%d KB) for FCE.\n", FCE_SIZE / 1024);
-			goto cont_alloc;
+			goto try_eft;
 		}
 		}
 
 
 		memset(tc, 0, FCE_SIZE);
 		memset(tc, 0, FCE_SIZE);
@@ -815,7 +796,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
 			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
 			    tc_dma);
 			    tc_dma);
 			ha->flags.fce_enabled = 0;
 			ha->flags.fce_enabled = 0;
-			goto cont_alloc;
+			goto try_eft;
 		}
 		}
 
 
 		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
 		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
@@ -825,6 +806,32 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 		ha->flags.fce_enabled = 1;
 		ha->flags.fce_enabled = 1;
 		ha->fce_dma = tc_dma;
 		ha->fce_dma = tc_dma;
 		ha->fce = tc;
 		ha->fce = tc;
+try_eft:
+		/* Allocate memory for Extended Trace Buffer. */
+		tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
+		    GFP_KERNEL);
+		if (!tc) {
+			qla_printk(KERN_WARNING, ha, "Unable to allocate "
+			    "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+			goto cont_alloc;
+		}
+
+		memset(tc, 0, EFT_SIZE);
+		rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
+		if (rval) {
+			qla_printk(KERN_WARNING, ha, "Unable to initialize "
+			    "EFT (%d).\n", rval);
+			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
+			    tc_dma);
+			goto cont_alloc;
+		}
+
+		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
+		    EFT_SIZE / 1024);
+
+		eft_size = EFT_SIZE;
+		ha->eft_dma = tc_dma;
+		ha->eft = tc;
 	}
 	}
 cont_alloc:
 cont_alloc:
 	req_q_size = ha->request_q_length * sizeof(request_t);
 	req_q_size = ha->request_q_length * sizeof(request_t);
@@ -1501,18 +1508,25 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
 		index = (ha->pdev->subsystem_device & 0xff);
 		index = (ha->pdev->subsystem_device & 0xff);
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES)
 		    index < QLA_MODEL_NAMES)
-			ha->model_desc = qla2x00_model_name[index * 2 + 1];
+			strncpy(ha->model_desc,
+			    qla2x00_model_name[index * 2 + 1],
+			    sizeof(ha->model_desc) - 1);
 	} else {
 	} else {
 		index = (ha->pdev->subsystem_device & 0xff);
 		index = (ha->pdev->subsystem_device & 0xff);
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES) {
 		    index < QLA_MODEL_NAMES) {
 			strcpy(ha->model_number,
 			strcpy(ha->model_number,
 			    qla2x00_model_name[index * 2]);
 			    qla2x00_model_name[index * 2]);
-			ha->model_desc = qla2x00_model_name[index * 2 + 1];
+			strncpy(ha->model_desc,
+			    qla2x00_model_name[index * 2 + 1],
+			    sizeof(ha->model_desc) - 1);
 		} else {
 		} else {
 			strcpy(ha->model_number, def);
 			strcpy(ha->model_number, def);
 		}
 		}
 	}
 	}
+	if (IS_FWI2_CAPABLE(ha))
+		qla2xxx_get_vpd_field(ha, "\x82", ha->model_desc,
+		    sizeof(ha->model_desc));
 }
 }
 
 
 /* On sparc systems, obtain port and node WWN from firmware
 /* On sparc systems, obtain port and node WWN from firmware
@@ -1864,12 +1878,11 @@ qla2x00_rport_del(void *data)
 {
 {
 	fc_port_t *fcport = data;
 	fc_port_t *fcport = data;
 	struct fc_rport *rport;
 	struct fc_rport *rport;
-	unsigned long flags;
 
 
-	spin_lock_irqsave(&fcport->rport_lock, flags);
+	spin_lock_irq(fcport->ha->host->host_lock);
 	rport = fcport->drport;
 	rport = fcport->drport;
 	fcport->drport = NULL;
 	fcport->drport = NULL;
-	spin_unlock_irqrestore(&fcport->rport_lock, flags);
+	spin_unlock_irq(fcport->ha->host->host_lock);
 	if (rport)
 	if (rport)
 		fc_remote_port_delete(rport);
 		fc_remote_port_delete(rport);
 }
 }
@@ -1898,7 +1911,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
 	atomic_set(&fcport->state, FCS_UNCONFIGURED);
 	atomic_set(&fcport->state, FCS_UNCONFIGURED);
 	fcport->flags = FCF_RLC_SUPPORT;
 	fcport->flags = FCF_RLC_SUPPORT;
 	fcport->supported_classes = FC_COS_UNSPECIFIED;
 	fcport->supported_classes = FC_COS_UNSPECIFIED;
-	spin_lock_init(&fcport->rport_lock);
 
 
 	return fcport;
 	return fcport;
 }
 }
@@ -2007,8 +2019,10 @@ qla2x00_configure_loop(scsi_qla_host_t *ha)
 	if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
 	if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
 		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
 		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
 			set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
 			set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
-		if (test_bit(RSCN_UPDATE, &save_flags))
+		if (test_bit(RSCN_UPDATE, &save_flags)) {
+			ha->flags.rscn_queue_overflow = 1;
 			set_bit(RSCN_UPDATE, &ha->dpc_flags);
 			set_bit(RSCN_UPDATE, &ha->dpc_flags);
+		}
 	}
 	}
 
 
 	return (rval);
 	return (rval);
@@ -2243,28 +2257,24 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
 {
 	struct fc_rport_identifiers rport_ids;
 	struct fc_rport_identifiers rport_ids;
 	struct fc_rport *rport;
 	struct fc_rport *rport;
-	unsigned long flags;
 
 
 	if (fcport->drport)
 	if (fcport->drport)
 		qla2x00_rport_del(fcport);
 		qla2x00_rport_del(fcport);
-	if (fcport->rport)
-		return;
 
 
 	rport_ids.node_name = wwn_to_u64(fcport->node_name);
 	rport_ids.node_name = wwn_to_u64(fcport->node_name);
 	rport_ids.port_name = wwn_to_u64(fcport->port_name);
 	rport_ids.port_name = wwn_to_u64(fcport->port_name);
 	rport_ids.port_id = fcport->d_id.b.domain << 16 |
 	rport_ids.port_id = fcport->d_id.b.domain << 16 |
 	    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
 	    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
 	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
 	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
-	rport = fc_remote_port_add(ha->host, 0, &rport_ids);
+	fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids);
 	if (!rport) {
 	if (!rport) {
 		qla_printk(KERN_WARNING, ha,
 		qla_printk(KERN_WARNING, ha,
 		    "Unable to allocate fc remote port!\n");
 		    "Unable to allocate fc remote port!\n");
 		return;
 		return;
 	}
 	}
-	spin_lock_irqsave(&fcport->rport_lock, flags);
-	fcport->rport = rport;
+	spin_lock_irq(fcport->ha->host->host_lock);
 	*((fc_port_t **)rport->dd_data) = fcport;
 	*((fc_port_t **)rport->dd_data) = fcport;
-	spin_unlock_irqrestore(&fcport->rport_lock, flags);
+	spin_unlock_irq(fcport->ha->host->host_lock);
 
 
 	rport->supported_classes = fcport->supported_classes;
 	rport->supported_classes = fcport->supported_classes;
 
 
@@ -2565,7 +2575,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
 		} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
 		} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
 			kfree(swl);
 			kfree(swl);
 			swl = NULL;
 			swl = NULL;
-		} else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
+		} else if (ql2xiidmaenable &&
+		    qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
 			qla2x00_gpsc(ha, swl);
 			qla2x00_gpsc(ha, swl);
 		}
 		}
 	}
 	}
@@ -3220,7 +3231,8 @@ qla2x00_update_fcports(scsi_qla_host_t *ha)
 
 
 	/* Go with deferred removal of rport references. */
 	/* Go with deferred removal of rport references. */
 	list_for_each_entry(fcport, &ha->fcports, list)
 	list_for_each_entry(fcport, &ha->fcports, list)
-		if (fcport->drport)
+		if (fcport->drport &&
+		    atomic_read(&fcport->state) != FCS_UNCONFIGURED)
 			qla2x00_rport_del(fcport);
 			qla2x00_rport_del(fcport);
 }
 }
 
 
@@ -3243,6 +3255,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 	if (ha->flags.online) {
 	if (ha->flags.online) {
 		ha->flags.online = 0;
 		ha->flags.online = 0;
 		clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 		clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		ha->qla_stats.total_isp_aborts++;
 
 
 		qla_printk(KERN_INFO, ha,
 		qla_printk(KERN_INFO, ha,
 		    "Performing ISP error recovery - ha= %p.\n", ha);
 		    "Performing ISP error recovery - ha= %p.\n", ha);
@@ -3283,17 +3296,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 			ha->isp_abort_cnt = 0;
 			ha->isp_abort_cnt = 0;
 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 
 
-			if (ha->eft) {
-				memset(ha->eft, 0, EFT_SIZE);
-				rval = qla2x00_enable_eft_trace(ha,
-				    ha->eft_dma, EFT_NUM_BUFFERS);
-				if (rval) {
-					qla_printk(KERN_WARNING, ha,
-					    "Unable to reinitialize EFT "
-					    "(%d).\n", rval);
-				}
-			}
-
 			if (ha->fce) {
 			if (ha->fce) {
 				ha->flags.fce_enabled = 1;
 				ha->flags.fce_enabled = 1;
 				memset(ha->fce, 0,
 				memset(ha->fce, 0,
@@ -3308,6 +3310,17 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 					ha->flags.fce_enabled = 0;
 					ha->flags.fce_enabled = 0;
 				}
 				}
 			}
 			}
+
+			if (ha->eft) {
+				memset(ha->eft, 0, EFT_SIZE);
+				rval = qla2x00_enable_eft_trace(ha,
+				    ha->eft_dma, EFT_NUM_BUFFERS);
+				if (rval) {
+					qla_printk(KERN_WARNING, ha,
+					    "Unable to reinitialize EFT "
+					    "(%d).\n", rval);
+				}
+			}
 		} else {	/* failed the ISP abort */
 		} else {	/* failed the ISP abort */
 			ha->flags.online = 1;
 			ha->flags.online = 1;
 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
@@ -4026,8 +4039,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 	ret = qla2x00_stop_firmware(ha);
 	ret = qla2x00_stop_firmware(ha);
 	for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
 	for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
 	    retries ; retries--) {
 	    retries ; retries--) {
-		qla2x00_reset_chip(ha);
-		if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
+		ha->isp_ops->reset_chip(ha);
+		if (ha->isp_ops->chip_diag(ha) != QLA_SUCCESS)
 			continue;
 			continue;
 		if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
 		if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
 			continue;
 			continue;
@@ -4049,7 +4062,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha)
 	rval = qla2x00_fw_ready(ha->parent);
 	rval = qla2x00_fw_ready(ha->parent);
 	if (rval == QLA_SUCCESS) {
 	if (rval == QLA_SUCCESS) {
 		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
 		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-		qla2x00_marker(ha->parent, 0, 0, MK_SYNC_ALL);
+		qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
 	}
 	}
 
 
 	ha->flags.management_server_logged_in = 0;
 	ha->flags.management_server_logged_in = 0;

+ 8 - 6
drivers/scsi/qla2xxx/qla_iocb.c

@@ -454,10 +454,11 @@ qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
 {
 {
 	int ret;
 	int ret;
 	unsigned long flags = 0;
 	unsigned long flags = 0;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&pha->hardware_lock, flags);
 	ret = __qla2x00_marker(ha, loop_id, lun, type);
 	ret = __qla2x00_marker(ha, loop_id, lun, type);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 
 
 	return (ret);
 	return (ret);
 }
 }
@@ -672,7 +673,7 @@ qla24xx_start_scsi(srb_t *sp)
 {
 {
 	int		ret, nseg;
 	int		ret, nseg;
 	unsigned long   flags;
 	unsigned long   flags;
-	scsi_qla_host_t	*ha;
+	scsi_qla_host_t	*ha, *pha;
 	struct scsi_cmnd *cmd;
 	struct scsi_cmnd *cmd;
 	uint32_t	*clr_ptr;
 	uint32_t	*clr_ptr;
 	uint32_t        index;
 	uint32_t        index;
@@ -686,6 +687,7 @@ qla24xx_start_scsi(srb_t *sp)
 	/* Setup device pointers. */
 	/* Setup device pointers. */
 	ret = 0;
 	ret = 0;
 	ha = sp->ha;
 	ha = sp->ha;
+	pha = to_qla_parent(ha);
 	reg = &ha->iobase->isp24;
 	reg = &ha->iobase->isp24;
 	cmd = sp->cmd;
 	cmd = sp->cmd;
 	/* So we know we haven't pci_map'ed anything yet */
 	/* So we know we haven't pci_map'ed anything yet */
@@ -700,7 +702,7 @@ qla24xx_start_scsi(srb_t *sp)
 	}
 	}
 
 
 	/* Acquire ring specific lock */
 	/* Acquire ring specific lock */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&pha->hardware_lock, flags);
 
 
 	/* Check for room in outstanding command list. */
 	/* Check for room in outstanding command list. */
 	handle = ha->current_outstanding_cmd;
 	handle = ha->current_outstanding_cmd;
@@ -795,14 +797,14 @@ qla24xx_start_scsi(srb_t *sp)
 	    ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
 	    ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
 		qla24xx_process_response_queue(ha);
 		qla24xx_process_response_queue(ha);
 
 
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 	return QLA_SUCCESS;
 	return QLA_SUCCESS;
 
 
 queuing_error:
 queuing_error:
 	if (tot_dsds)
 	if (tot_dsds)
 		scsi_dma_unmap(cmd);
 		scsi_dma_unmap(cmd);
 
 
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 
 
 	return QLA_FUNCTION_FAILED;
 	return QLA_FUNCTION_FAILED;
 }
 }

+ 0 - 4
drivers/scsi/qla2xxx/qla_isr.c

@@ -542,10 +542,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
 		break;
 		break;
 
 
 	case MBA_PORT_UPDATE:		/* Port database update */
 	case MBA_PORT_UPDATE:		/* Port database update */
-		/* Only handle SCNs for our Vport index. */
-		if (ha->parent && ha->vp_idx != (mb[3] & 0xff))
-			break;
-
 		/*
 		/*
 		 * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
 		 * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
 		 * event etc. earlier indicating loop is down) then process
 		 * event etc. earlier indicating loop is down) then process

+ 6 - 3
drivers/scsi/qla2xxx/qla_mbx.c

@@ -918,6 +918,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
 	rval = qla2x00_mailbox_command(ha, mcp);
 	rval = qla2x00_mailbox_command(ha, mcp);
 	if (mcp->mb[0] == MBS_COMMAND_ERROR)
 	if (mcp->mb[0] == MBS_COMMAND_ERROR)
 		rval = QLA_COMMAND_ERROR;
 		rval = QLA_COMMAND_ERROR;
+	else if (mcp->mb[0] == MBS_INVALID_COMMAND)
+		rval = QLA_INVALID_COMMAND;
 
 
 	/* Return data. */
 	/* Return data. */
 	*id = mcp->mb[1];
 	*id = mcp->mb[1];
@@ -2161,17 +2163,18 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
 	struct abort_entry_24xx *abt;
 	struct abort_entry_24xx *abt;
 	dma_addr_t	abt_dma;
 	dma_addr_t	abt_dma;
 	uint32_t	handle;
 	uint32_t	handle;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
 
 	fcport = sp->fcport;
 	fcport = sp->fcport;
 
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&pha->hardware_lock, flags);
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
-		if (ha->outstanding_cmds[handle] == sp)
+		if (pha->outstanding_cmds[handle] == sp)
 			break;
 			break;
 	}
 	}
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 	if (handle == MAX_OUTSTANDING_COMMANDS) {
 	if (handle == MAX_OUTSTANDING_COMMANDS) {
 		/* Command not found. */
 		/* Command not found. */
 		return QLA_FUNCTION_FAILED;
 		return QLA_FUNCTION_FAILED;

+ 6 - 10
drivers/scsi/qla2xxx/qla_mid.c

@@ -43,6 +43,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
 
 
 	set_bit(vp_id, ha->vp_idx_map);
 	set_bit(vp_id, ha->vp_idx_map);
 	ha->num_vhosts++;
 	ha->num_vhosts++;
+	ha->cur_vport_count++;
 	vha->vp_idx = vp_id;
 	vha->vp_idx = vp_id;
 	list_add_tail(&vha->vp_list, &ha->vp_list);
 	list_add_tail(&vha->vp_list, &ha->vp_list);
 	mutex_unlock(&ha->vport_lock);
 	mutex_unlock(&ha->vport_lock);
@@ -58,6 +59,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
 	mutex_lock(&ha->vport_lock);
 	mutex_lock(&ha->vport_lock);
 	vp_id = vha->vp_idx;
 	vp_id = vha->vp_idx;
 	ha->num_vhosts--;
 	ha->num_vhosts--;
+	ha->cur_vport_count--;
 	clear_bit(vp_id, ha->vp_idx_map);
 	clear_bit(vp_id, ha->vp_idx_map);
 	list_del(&vha->vp_list);
 	list_del(&vha->vp_list);
 	mutex_unlock(&ha->vport_lock);
 	mutex_unlock(&ha->vport_lock);
@@ -103,8 +105,8 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
 		    "loop_id=0x%04x :%x\n",
 		    "loop_id=0x%04x :%x\n",
 		    vha->host_no, fcport->loop_id, fcport->vp_idx));
 		    vha->host_no, fcport->loop_id, fcport->vp_idx));
 
 
-		atomic_set(&fcport->state, FCS_DEVICE_DEAD);
 		qla2x00_mark_device_lost(vha, fcport, 0, 0);
 		qla2x00_mark_device_lost(vha, fcport, 0, 0);
+		atomic_set(&fcport->state, FCS_UNCONFIGURED);
 	}
 	}
 }
 }
 
 
@@ -276,7 +278,8 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 		clear_bit(RESET_ACTIVE, &vha->dpc_flags);
 		clear_bit(RESET_ACTIVE, &vha->dpc_flags);
 	}
 	}
 
 
-	if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+	if (atomic_read(&vha->vp_state) == VP_ACTIVE &&
+	    test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
 		if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
 		if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
 			qla2x00_loop_resync(vha);
 			qla2x00_loop_resync(vha);
 			clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
 			clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
@@ -390,7 +393,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	vha->parent = ha;
 	vha->parent = ha;
 	vha->fc_vport = fc_vport;
 	vha->fc_vport = fc_vport;
 	vha->device_flags = 0;
 	vha->device_flags = 0;
-	vha->instance = num_hosts;
 	vha->vp_idx = qla24xx_allocate_vp_id(vha);
 	vha->vp_idx = qla24xx_allocate_vp_id(vha);
 	if (vha->vp_idx > ha->max_npiv_vports) {
 	if (vha->vp_idx > ha->max_npiv_vports) {
 		DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
 		DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
@@ -428,7 +430,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_lun = MAX_LUNS;
 	host->max_lun = MAX_LUNS;
-	host->unique_id = vha->instance;
+	host->unique_id = host->host_no;
 	host->max_id = MAX_TARGETS_2200;
 	host->max_id = MAX_TARGETS_2200;
 	host->transportt = qla2xxx_transport_vport_template;
 	host->transportt = qla2xxx_transport_vport_template;
 
 
@@ -436,12 +438,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	    vha->host_no, vha));
 	    vha->host_no, vha));
 
 
 	vha->flags.init_done = 1;
 	vha->flags.init_done = 1;
-	num_hosts++;
-
-	mutex_lock(&ha->vport_lock);
-	set_bit(vha->vp_idx, ha->vp_idx_map);
-	ha->cur_vport_count++;
-	mutex_unlock(&ha->vport_lock);
 
 
 	return vha;
 	return vha;
 
 

+ 59 - 35
drivers/scsi/qla2xxx/qla_os.c

@@ -27,7 +27,6 @@ char qla2x00_version_str[40];
  */
  */
 static struct kmem_cache *srb_cachep;
 static struct kmem_cache *srb_cachep;
 
 
-int num_hosts;
 int ql2xlogintimeout = 20;
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
 MODULE_PARM_DESC(ql2xlogintimeout,
@@ -87,6 +86,13 @@ MODULE_PARM_DESC(ql2xqfullrampup,
 		"depth for a device after a queue-full condition has been "
 		"depth for a device after a queue-full condition has been "
 		"detected.  Default is 120 seconds.");
 		"detected.  Default is 120 seconds.");
 
 
+int ql2xiidmaenable=1;
+module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xiidmaenable,
+		"Enables iIDMA settings "
+		"Default is 1 - perform iIDMA. 0 - no iIDMA.");
+
+
 /*
 /*
  * SCSI host template entry points
  * SCSI host template entry points
  */
  */
@@ -388,7 +394,7 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	}
 	}
 
 
 	/* Close window on fcport/rport state-transitioning. */
 	/* Close window on fcport/rport state-transitioning. */
-	if (!*(fc_port_t **)rport->dd_data) {
+	if (fcport->drport) {
 		cmd->result = DID_IMM_RETRY << 16;
 		cmd->result = DID_IMM_RETRY << 16;
 		goto qc_fail_command;
 		goto qc_fail_command;
 	}
 	}
@@ -443,7 +449,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	int rval;
 	int rval;
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
-	if (unlikely(pci_channel_offline(ha->pdev))) {
+	if (unlikely(pci_channel_offline(pha->pdev))) {
 		cmd->result = DID_REQUEUE << 16;
 		cmd->result = DID_REQUEUE << 16;
 		goto qc24_fail_command;
 		goto qc24_fail_command;
 	}
 	}
@@ -455,7 +461,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	}
 	}
 
 
 	/* Close window on fcport/rport state-transitioning. */
 	/* Close window on fcport/rport state-transitioning. */
-	if (!*(fc_port_t **)rport->dd_data) {
+	if (fcport->drport) {
 		cmd->result = DID_IMM_RETRY << 16;
 		cmd->result = DID_IMM_RETRY << 16;
 		goto qc24_fail_command;
 		goto qc24_fail_command;
 	}
 	}
@@ -617,6 +623,40 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
 	return (return_status);
 	return (return_status);
 }
 }
 
 
+void
+qla2x00_abort_fcport_cmds(fc_port_t *fcport)
+{
+	int cnt;
+	unsigned long flags;
+	srb_t *sp;
+	scsi_qla_host_t *ha = fcport->ha;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
+
+	spin_lock_irqsave(&pha->hardware_lock, flags);
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		sp = pha->outstanding_cmds[cnt];
+		if (!sp)
+			continue;
+		if (sp->fcport != fcport)
+			continue;
+
+		spin_unlock_irqrestore(&pha->hardware_lock, flags);
+		if (ha->isp_ops->abort_command(ha, sp)) {
+			DEBUG2(qla_printk(KERN_WARNING, ha,
+			    "Abort failed --  %lx\n", sp->cmd->serial_number));
+		} else {
+			if (qla2x00_eh_wait_on_command(ha, sp->cmd) !=
+			    QLA_SUCCESS)
+				DEBUG2(qla_printk(KERN_WARNING, ha,
+				    "Abort failed while waiting --  %lx\n",
+				    sp->cmd->serial_number));
+
+		}
+		spin_lock_irqsave(&pha->hardware_lock, flags);
+	}
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
+}
+
 static void
 static void
 qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
 qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
 {
 {
@@ -1073,7 +1113,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
 	else
 	else
 		scsi_deactivate_tcq(sdev, ha->max_q_depth);
 		scsi_deactivate_tcq(sdev, ha->max_q_depth);
 
 
-	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+	rport->dev_loss_tmo = ha->port_down_retry_count;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1629,9 +1669,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	}
 	}
 	host->can_queue = ha->request_q_length + 128;
 	host->can_queue = ha->request_q_length + 128;
 
 
-	/* load the F/W, read paramaters, and init the H/W */
-	ha->instance = num_hosts;
-
 	mutex_init(&ha->vport_lock);
 	mutex_init(&ha->vport_lock);
 	init_completion(&ha->mbx_cmd_comp);
 	init_completion(&ha->mbx_cmd_comp);
 	complete(&ha->mbx_cmd_comp);
 	complete(&ha->mbx_cmd_comp);
@@ -1679,7 +1716,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 
 	host->this_id = 255;
 	host->this_id = 255;
 	host->cmd_per_lun = 3;
 	host->cmd_per_lun = 3;
-	host->unique_id = ha->instance;
+	host->unique_id = host->host_no;
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_lun = MAX_LUNS;
 	host->max_lun = MAX_LUNS;
@@ -1700,8 +1737,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	ha->flags.init_done = 1;
 	ha->flags.init_done = 1;
 	ha->flags.online = 1;
 	ha->flags.online = 1;
 
 
-	num_hosts++;
-
 	ret = scsi_add_host(host, &pdev->dev);
 	ret = scsi_add_host(host, &pdev->dev);
 	if (ret)
 	if (ret)
 		goto probe_failed;
 		goto probe_failed;
@@ -1813,27 +1848,21 @@ static inline void
 qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
 qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
     int defer)
     int defer)
 {
 {
-	unsigned long flags;
 	struct fc_rport *rport;
 	struct fc_rport *rport;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	if (!fcport->rport)
 	if (!fcport->rport)
 		return;
 		return;
 
 
 	rport = fcport->rport;
 	rport = fcport->rport;
 	if (defer) {
 	if (defer) {
-		spin_lock_irqsave(&fcport->rport_lock, flags);
+		spin_lock_irq(ha->host->host_lock);
 		fcport->drport = rport;
 		fcport->drport = rport;
-		fcport->rport = NULL;
-		*(fc_port_t **)rport->dd_data = NULL;
-		spin_unlock_irqrestore(&fcport->rport_lock, flags);
-		set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
-	} else {
-		spin_lock_irqsave(&fcport->rport_lock, flags);
-		fcport->rport = NULL;
-		*(fc_port_t **)rport->dd_data = NULL;
-		spin_unlock_irqrestore(&fcport->rport_lock, flags);
+		spin_unlock_irq(ha->host->host_lock);
+		set_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags);
+		qla2xxx_wake_dpc(pha);
+	} else
 		fc_remote_port_delete(rport);
 		fc_remote_port_delete(rport);
-	}
 }
 }
 
 
 /*
 /*
@@ -1903,7 +1932,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	list_for_each_entry(fcport, &pha->fcports, list) {
 	list_for_each_entry(fcport, &pha->fcports, list) {
-		if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
+		if (ha->vp_idx != fcport->vp_idx)
 			continue;
 			continue;
 		/*
 		/*
 		 * No point in marking the device as lost, if the device is
 		 * No point in marking the device as lost, if the device is
@@ -1911,17 +1940,10 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 		 */
 		 */
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
 			continue;
 			continue;
-		if (atomic_read(&fcport->state) == FCS_ONLINE) {
-			if (defer)
-				qla2x00_schedule_rport_del(ha, fcport, defer);
-			else if (ha->vp_idx == fcport->vp_idx)
-				qla2x00_schedule_rport_del(ha, fcport, defer);
-		}
+		if (atomic_read(&fcport->state) == FCS_ONLINE)
+			qla2x00_schedule_rport_del(ha, fcport, defer);
 		atomic_set(&fcport->state, FCS_DEVICE_LOST);
 		atomic_set(&fcport->state, FCS_DEVICE_LOST);
 	}
 	}
-
-	if (defer)
-		qla2xxx_wake_dpc(ha);
 }
 }
 
 
 /*
 /*
@@ -2156,7 +2178,7 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
 static int
 static int
 qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
 qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
 {
 {
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	if (!locked)
 	if (!locked)
@@ -2313,8 +2335,10 @@ qla2x00_do_dpc(void *data)
 			    ha->host_no));
 			    ha->host_no));
 		}
 		}
 
 
-		if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags))
+		if (test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) {
 			qla2x00_update_fcports(ha);
 			qla2x00_update_fcports(ha);
+			clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
+		}
 
 
 		if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
 		if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
 		    (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {
 		    (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {

+ 45 - 3
drivers/scsi/qla2xxx/qla_sup.c

@@ -869,11 +869,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
 	uint32_t i;
 	uint32_t i;
 	uint32_t *dwptr;
 	uint32_t *dwptr;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-	unsigned long flags;
 
 
 	ret = QLA_SUCCESS;
 	ret = QLA_SUCCESS;
 
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
 	/* Enable flash write. */
 	/* Enable flash write. */
 	WRT_REG_DWORD(&reg->ctrl_status,
 	WRT_REG_DWORD(&reg->ctrl_status,
 	    RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
 	    RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
@@ -907,7 +905,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
 	WRT_REG_DWORD(&reg->ctrl_status,
 	WRT_REG_DWORD(&reg->ctrl_status,
 	    RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
 	    RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
 	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */
 	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -2305,6 +2302,51 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
 	return ret;
 	return ret;
 }
 }
 
 
+static int
+qla2xxx_is_vpd_valid(uint8_t *pos, uint8_t *end)
+{
+	if (pos >= end || *pos != 0x82)
+		return 0;
+
+	pos += 3 + pos[1];
+	if (pos >= end || *pos != 0x90)
+		return 0;
+
+	pos += 3 + pos[1];
+	if (pos >= end || *pos != 0x78)
+		return 0;
+
+	return 1;
+}
+
+int
+qla2xxx_get_vpd_field(scsi_qla_host_t *ha, char *key, char *str, size_t size)
+{
+	uint8_t *pos = ha->vpd;
+	uint8_t *end = pos + ha->vpd_size;
+	int len = 0;
+
+	if (!IS_FWI2_CAPABLE(ha) || !qla2xxx_is_vpd_valid(pos, end))
+		return 0;
+
+	while (pos < end && *pos != 0x78) {
+		len = (*pos == 0x82) ? pos[1] : pos[2];
+
+		if (!strncmp(pos, key, strlen(key)))
+			break;
+
+		if (*pos != 0x90 && *pos != 0x91)
+			pos += len;
+
+		pos += 3;
+	}
+
+	if (pos < end - len && *pos != 0x78)
+		return snprintf(str, size, "%.*s", len, pos + 3);
+
+	return 0;
+}
+
 static int
 static int
 qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
 qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
 {
 {

+ 1 - 1
drivers/scsi/qla2xxx/qla_version.h

@@ -7,7 +7,7 @@
 /*
 /*
  * Driver version
  * Driver version
  */
  */
-#define QLA2XXX_VERSION      "8.02.01-k4"
+#define QLA2XXX_VERSION      "8.02.01-k6"
 
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	2
 #define QLA_DRIVER_MINOR_VER	2

+ 3 - 1
drivers/scsi/qla4xxx/ql4_os.c

@@ -46,6 +46,8 @@ MODULE_PARM_DESC(ql4xextended_error_logging,
 
 
 int ql4_mod_unload = 0;
 int ql4_mod_unload = 0;
 
 
+#define QL4_DEF_QDEPTH 32
+
 /*
 /*
  * SCSI host template entry points
  * SCSI host template entry points
  */
  */
@@ -1387,7 +1389,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev)
 
 
 	sdev->hostdata = ddb;
 	sdev->hostdata = ddb;
 	sdev->tagged_supported = 1;
 	sdev->tagged_supported = 1;
-	scsi_activate_tcq(sdev, sdev->host->can_queue);
+	scsi_activate_tcq(sdev, QL4_DEF_QDEPTH);
 	return 0;
 	return 0;
 }
 }
 
 

+ 48 - 7
drivers/scsi/scsi.c

@@ -197,10 +197,42 @@ static void
 scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
 scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
 			 struct scsi_cmnd *cmd)
 			 struct scsi_cmnd *cmd)
 {
 {
+	if (cmd->prot_sdb)
+		kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
+
 	kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
 	kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
 	kmem_cache_free(pool->cmd_slab, cmd);
 	kmem_cache_free(pool->cmd_slab, cmd);
 }
 }
 
 
+/**
+ * scsi_host_alloc_command - internal function to allocate command
+ * @shost:	SCSI host whose pool to allocate from
+ * @gfp_mask:	mask for the allocation
+ *
+ * Returns a fully allocated command with sense buffer and protection
+ * data buffer (where applicable) or NULL on failure
+ */
+static struct scsi_cmnd *
+scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
+{
+	struct scsi_cmnd *cmd;
+
+	cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+	if (!cmd)
+		return NULL;
+
+	if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
+		cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
+
+		if (!cmd->prot_sdb) {
+			scsi_pool_free_command(shost->cmd_pool, cmd);
+			return NULL;
+		}
+	}
+
+	return cmd;
+}
+
 /**
 /**
  * __scsi_get_command - Allocate a struct scsi_cmnd
  * __scsi_get_command - Allocate a struct scsi_cmnd
  * @shost: host to transmit command
  * @shost: host to transmit command
@@ -214,7 +246,7 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 	struct scsi_cmnd *cmd;
 	struct scsi_cmnd *cmd;
 	unsigned char *buf;
 	unsigned char *buf;
 
 
-	cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+	cmd = scsi_host_alloc_command(shost, gfp_mask);
 
 
 	if (unlikely(!cmd)) {
 	if (unlikely(!cmd)) {
 		unsigned long flags;
 		unsigned long flags;
@@ -457,7 +489,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
 	/*
 	/*
 	 * Get one backup command for this host.
 	 * Get one backup command for this host.
 	 */
 	 */
-	cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+	cmd = scsi_host_alloc_command(shost, gfp_mask);
 	if (!cmd) {
 	if (!cmd) {
 		scsi_put_host_cmd_pool(gfp_mask);
 		scsi_put_host_cmd_pool(gfp_mask);
 		shost->cmd_pool = NULL;
 		shost->cmd_pool = NULL;
@@ -902,11 +934,20 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 
 
 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 
 
-	/* Check to see if the queue is managed by the block layer.
-	 * If it is, and we fail to adjust the depth, exit. */
-	if (blk_queue_tagged(sdev->request_queue) &&
-	    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
-		goto out;
+	/*
+	 * Check to see if the queue is managed by the block layer.
+	 * If it is, and we fail to adjust the depth, exit.
+	 *
+	 * Do not resize the tag map if it is a host wide share bqt,
+	 * because the size should be the hosts's can_queue. If there
+	 * is more IO than the LLD's can_queue (so there are not enuogh
+	 * tags) request_fn's host queue ready check will handle it.
+	 */
+	if (!sdev->host->bqt) {
+		if (blk_queue_tagged(sdev->request_queue) &&
+		    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
+			goto out;
+	}
 
 
 	sdev->queue_depth = tags;
 	sdev->queue_depth = tags;
 	switch (tagged) {
 	switch (tagged) {

+ 6 - 6
drivers/scsi/scsi_debug.c

@@ -1753,7 +1753,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
 		if (!open_devip) {
 		if (!open_devip) {
 			printk(KERN_ERR "%s: out of memory at line %d\n",
 			printk(KERN_ERR "%s: out of memory at line %d\n",
-				__FUNCTION__, __LINE__);
+				__func__, __LINE__);
 			return NULL;
 			return NULL;
 		}
 		}
 	}
 	}
@@ -2656,7 +2656,7 @@ static int sdebug_add_adapter(void)
         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
         if (NULL == sdbg_host) {
         if (NULL == sdbg_host) {
                 printk(KERN_ERR "%s: out of memory at line %d\n",
                 printk(KERN_ERR "%s: out of memory at line %d\n",
-                       __FUNCTION__, __LINE__);
+                       __func__, __LINE__);
                 return -ENOMEM;
                 return -ENOMEM;
         }
         }
 
 
@@ -2667,7 +2667,7 @@ static int sdebug_add_adapter(void)
 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
 		if (!sdbg_devinfo) {
 		if (!sdbg_devinfo) {
                         printk(KERN_ERR "%s: out of memory at line %d\n",
                         printk(KERN_ERR "%s: out of memory at line %d\n",
-                               __FUNCTION__, __LINE__);
+                               __func__, __LINE__);
                         error = -ENOMEM;
                         error = -ENOMEM;
 			goto clean;
 			goto clean;
                 }
                 }
@@ -2987,7 +2987,7 @@ static int sdebug_driver_probe(struct device * dev)
 
 
         hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
         hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
         if (NULL == hpnt) {
         if (NULL == hpnt) {
-                printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
+                printk(KERN_ERR "%s: scsi_register failed\n", __func__);
                 error = -ENODEV;
                 error = -ENODEV;
 		return error;
 		return error;
         }
         }
@@ -3002,7 +3002,7 @@ static int sdebug_driver_probe(struct device * dev)
 
 
         error = scsi_add_host(hpnt, &sdbg_host->dev);
         error = scsi_add_host(hpnt, &sdbg_host->dev);
         if (error) {
         if (error) {
-                printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
+                printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
                 error = -ENODEV;
                 error = -ENODEV;
 		scsi_host_put(hpnt);
 		scsi_host_put(hpnt);
         } else
         } else
@@ -3021,7 +3021,7 @@ static int sdebug_driver_remove(struct device * dev)
 
 
 	if (!sdbg_host) {
 	if (!sdbg_host) {
 		printk(KERN_ERR "%s: Unable to locate host info\n",
 		printk(KERN_ERR "%s: Unable to locate host info\n",
-		       __FUNCTION__);
+		       __func__);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 

+ 3 - 3
drivers/scsi/scsi_devinfo.c

@@ -272,7 +272,7 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
 	}
 	}
 	if (from_length > to_length)
 	if (from_length > to_length)
 		 printk(KERN_WARNING "%s: %s string '%s' is too long\n",
 		 printk(KERN_WARNING "%s: %s string '%s' is too long\n",
-			__FUNCTION__, name, from);
+			__func__, name, from);
 }
 }
 
 
 /**
 /**
@@ -298,7 +298,7 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
 
 
 	devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL);
 	devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL);
 	if (!devinfo) {
 	if (!devinfo) {
-		printk(KERN_ERR "%s: no memory\n", __FUNCTION__);
+		printk(KERN_ERR "%s: no memory\n", __func__);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
@@ -363,7 +363,7 @@ static int scsi_dev_info_list_add_str(char *dev_list)
 			strflags = strsep(&next, next_check);
 			strflags = strsep(&next, next_check);
 		if (!model || !strflags) {
 		if (!model || !strflags) {
 			printk(KERN_ERR "%s: bad dev info string '%s' '%s'"
 			printk(KERN_ERR "%s: bad dev info string '%s' '%s'"
-			       " '%s'\n", __FUNCTION__, vendor, model,
+			       " '%s'\n", __func__, vendor, model,
 			       strflags);
 			       strflags);
 			res = -EINVAL;
 			res = -EINVAL;
 		} else
 		} else

+ 21 - 13
drivers/scsi/scsi_error.c

@@ -139,7 +139,7 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
 	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
 	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
 
 
 	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
 	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
-					  " %d, (%p)\n", __FUNCTION__,
+					  " %d, (%p)\n", __func__,
 					  scmd, timeout, complete));
 					  scmd, timeout, complete));
 
 
 	add_timer(&scmd->eh_timeout);
 	add_timer(&scmd->eh_timeout);
@@ -163,7 +163,7 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
 	rtn = del_timer(&scmd->eh_timeout);
 	rtn = del_timer(&scmd->eh_timeout);
 
 
 	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
 	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
-					 " rtn: %d\n", __FUNCTION__,
+					 " rtn: %d\n", __func__,
 					 scmd, rtn));
 					 scmd, rtn));
 
 
 	scmd->eh_timeout.data = (unsigned long)NULL;
 	scmd->eh_timeout.data = (unsigned long)NULL;
@@ -233,7 +233,7 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev)
 
 
 	online = scsi_device_online(sdev);
 	online = scsi_device_online(sdev);
 
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__,
+	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __func__,
 					  online));
 					  online));
 
 
 	return online;
 	return online;
@@ -271,7 +271,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
 			SCSI_LOG_ERROR_RECOVERY(3,
 			SCSI_LOG_ERROR_RECOVERY(3,
 				sdev_printk(KERN_INFO, sdev,
 				sdev_printk(KERN_INFO, sdev,
 					    "%s: cmds failed: %d, cancel: %d\n",
 					    "%s: cmds failed: %d, cancel: %d\n",
-					    __FUNCTION__, cmd_failed,
+					    __func__, cmd_failed,
 					    cmd_cancel));
 					    cmd_cancel));
 			cmd_cancel = 0;
 			cmd_cancel = 0;
 			cmd_failed = 0;
 			cmd_failed = 0;
@@ -344,6 +344,9 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
 		return /* soft_error */ SUCCESS;
 		return /* soft_error */ SUCCESS;
 
 
 	case ABORTED_COMMAND:
 	case ABORTED_COMMAND:
+		if (sshdr.asc == 0x10) /* DIF */
+			return SUCCESS;
+
 		return NEEDS_RETRY;
 		return NEEDS_RETRY;
 	case NOT_READY:
 	case NOT_READY:
 	case UNIT_ATTENTION:
 	case UNIT_ATTENTION:
@@ -470,7 +473,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
 
 
 	SCSI_LOG_ERROR_RECOVERY(3,
 	SCSI_LOG_ERROR_RECOVERY(3,
 		printk("%s scmd: %p result: %x\n",
 		printk("%s scmd: %p result: %x\n",
-			__FUNCTION__, scmd, scmd->result));
+			__func__, scmd, scmd->result));
 
 
 	eh_action = scmd->device->host->eh_action;
 	eh_action = scmd->device->host->eh_action;
 	if (eh_action)
 	if (eh_action)
@@ -487,7 +490,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 	int rtn;
 	int rtn;
 
 
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
-					  __FUNCTION__));
+					  __func__));
 
 
 	if (!scmd->device->host->hostt->eh_host_reset_handler)
 	if (!scmd->device->host->hostt->eh_host_reset_handler)
 		return FAILED;
 		return FAILED;
@@ -516,7 +519,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
 	int rtn;
 	int rtn;
 
 
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
-					  __FUNCTION__));
+					  __func__));
 
 
 	if (!scmd->device->host->hostt->eh_bus_reset_handler)
 	if (!scmd->device->host->hostt->eh_bus_reset_handler)
 		return FAILED;
 		return FAILED;
@@ -664,7 +667,10 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
 	ses->sdb = scmd->sdb;
 	ses->sdb = scmd->sdb;
 	ses->next_rq = scmd->request->next_rq;
 	ses->next_rq = scmd->request->next_rq;
 	ses->result = scmd->result;
 	ses->result = scmd->result;
+	ses->underflow = scmd->underflow;
+	ses->prot_op = scmd->prot_op;
 
 
+	scmd->prot_op = SCSI_PROT_NORMAL;
 	scmd->cmnd = ses->eh_cmnd;
 	scmd->cmnd = ses->eh_cmnd;
 	memset(scmd->cmnd, 0, BLK_MAX_CDB);
 	memset(scmd->cmnd, 0, BLK_MAX_CDB);
 	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
 	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
@@ -722,6 +728,8 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 	scmd->sdb = ses->sdb;
 	scmd->sdb = ses->sdb;
 	scmd->request->next_rq = ses->next_rq;
 	scmd->request->next_rq = ses->next_rq;
 	scmd->result = ses->result;
 	scmd->result = ses->result;
+	scmd->underflow = ses->underflow;
+	scmd->prot_op = ses->prot_op;
 }
 }
 EXPORT_SYMBOL(scsi_eh_restore_cmnd);
 EXPORT_SYMBOL(scsi_eh_restore_cmnd);
 
 
@@ -766,7 +774,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
 
 
 	SCSI_LOG_ERROR_RECOVERY(3,
 	SCSI_LOG_ERROR_RECOVERY(3,
 		printk("%s: scmd: %p, timeleft: %ld\n",
 		printk("%s: scmd: %p, timeleft: %ld\n",
-			__FUNCTION__, scmd, timeleft));
+			__func__, scmd, timeleft));
 
 
 	/*
 	/*
 	 * If there is time left scsi_eh_done got called, and we will
 	 * If there is time left scsi_eh_done got called, and we will
@@ -778,7 +786,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
 		rtn = scsi_eh_completed_normally(scmd);
 		rtn = scsi_eh_completed_normally(scmd);
 		SCSI_LOG_ERROR_RECOVERY(3,
 		SCSI_LOG_ERROR_RECOVERY(3,
 			printk("%s: scsi_eh_completed_normally %x\n",
 			printk("%s: scsi_eh_completed_normally %x\n",
-			       __FUNCTION__, rtn));
+			       __func__, rtn));
 
 
 		switch (rtn) {
 		switch (rtn) {
 		case SUCCESS:
 		case SUCCESS:
@@ -913,7 +921,7 @@ retry_tur:
 	rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0);
 	rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0);
 
 
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
-		__FUNCTION__, scmd, rtn));
+		__func__, scmd, rtn));
 
 
 	switch (rtn) {
 	switch (rtn) {
 	case NEEDS_RETRY:
 	case NEEDS_RETRY:
@@ -1296,7 +1304,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
 	if (!scsi_device_online(scmd->device)) {
 	if (!scsi_device_online(scmd->device)) {
 		SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report"
 		SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report"
 						  " as SUCCESS\n",
 						  " as SUCCESS\n",
-						  __FUNCTION__));
+						  __func__));
 		return SUCCESS;
 		return SUCCESS;
 	}
 	}
 
 
@@ -1511,7 +1519,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
 	 * ioctls to queued block devices.
 	 * ioctls to queued block devices.
 	 */
 	 */
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
-					  __FUNCTION__));
+					  __func__));
 
 
 	spin_lock_irqsave(shost->host_lock, flags);
 	spin_lock_irqsave(shost->host_lock, flags);
 	if (scsi_host_set_state(shost, SHOST_RUNNING))
 	if (scsi_host_set_state(shost, SHOST_RUNNING))
@@ -1835,7 +1843,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
 	 */
 	 */
 	SCSI_LOG_ERROR_RECOVERY(3,
 	SCSI_LOG_ERROR_RECOVERY(3,
 		printk("%s: waking up host to restart after TMF\n",
 		printk("%s: waking up host to restart after TMF\n",
-		__FUNCTION__));
+		__func__));
 
 
 	wake_up(&shost->host_wait);
 	wake_up(&shost->host_wait);
 
 

+ 49 - 6
drivers/scsi/scsi_lib.c

@@ -65,7 +65,7 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = {
 };
 };
 #undef SP
 #undef SP
 
 
-static struct kmem_cache *scsi_sdb_cache;
+struct kmem_cache *scsi_sdb_cache;
 
 
 static void scsi_run_queue(struct request_queue *q);
 static void scsi_run_queue(struct request_queue *q);
 
 
@@ -787,6 +787,9 @@ void scsi_release_buffers(struct scsi_cmnd *cmd)
 		kmem_cache_free(scsi_sdb_cache, bidi_sdb);
 		kmem_cache_free(scsi_sdb_cache, bidi_sdb);
 		cmd->request->next_rq->special = NULL;
 		cmd->request->next_rq->special = NULL;
 	}
 	}
+
+	if (scsi_prot_sg_count(cmd))
+		scsi_free_sgtable(cmd->prot_sdb);
 }
 }
 EXPORT_SYMBOL(scsi_release_buffers);
 EXPORT_SYMBOL(scsi_release_buffers);
 
 
@@ -947,9 +950,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 				 * 6-byte command.
 				 * 6-byte command.
 				 */
 				 */
 				scsi_requeue_command(q, cmd);
 				scsi_requeue_command(q, cmd);
-				return;
-			} else {
+			} else if (sshdr.asc == 0x10) /* DIX */
+				scsi_end_request(cmd, -EIO, this_count, 0);
+			else
 				scsi_end_request(cmd, -EIO, this_count, 1);
 				scsi_end_request(cmd, -EIO, this_count, 1);
+			return;
+		case ABORTED_COMMAND:
+			if (sshdr.asc == 0x10) { /* DIF */
+				scsi_end_request(cmd, -EIO, this_count, 0);
 				return;
 				return;
 			}
 			}
 			break;
 			break;
@@ -1072,6 +1080,26 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 			goto err_exit;
 			goto err_exit;
 	}
 	}
 
 
+	if (blk_integrity_rq(cmd->request)) {
+		struct scsi_data_buffer *prot_sdb = cmd->prot_sdb;
+		int ivecs, count;
+
+		BUG_ON(prot_sdb == NULL);
+		ivecs = blk_rq_count_integrity_sg(cmd->request);
+
+		if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask)) {
+			error = BLKPREP_DEFER;
+			goto err_exit;
+		}
+
+		count = blk_rq_map_integrity_sg(cmd->request,
+						prot_sdb->table.sgl);
+		BUG_ON(unlikely(count > ivecs));
+
+		cmd->prot_sdb = prot_sdb;
+		cmd->prot_sdb->table.nents = count;
+	}
+
 	return BLKPREP_OK ;
 	return BLKPREP_OK ;
 
 
 err_exit:
 err_exit:
@@ -1367,7 +1395,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
 
 
 	if (unlikely(cmd == NULL)) {
 	if (unlikely(cmd == NULL)) {
 		printk(KERN_CRIT "impossible request in %s.\n",
 		printk(KERN_CRIT "impossible request in %s.\n",
-				 __FUNCTION__);
+				 __func__);
 		BUG();
 		BUG();
 	}
 	}
 
 
@@ -1491,12 +1519,27 @@ static void scsi_request_fn(struct request_queue *q)
 			printk(KERN_CRIT "impossible request in %s.\n"
 			printk(KERN_CRIT "impossible request in %s.\n"
 					 "please mail a stack trace to "
 					 "please mail a stack trace to "
 					 "linux-scsi@vger.kernel.org\n",
 					 "linux-scsi@vger.kernel.org\n",
-					 __FUNCTION__);
+					 __func__);
 			blk_dump_rq_flags(req, "foo");
 			blk_dump_rq_flags(req, "foo");
 			BUG();
 			BUG();
 		}
 		}
 		spin_lock(shost->host_lock);
 		spin_lock(shost->host_lock);
 
 
+		/*
+		 * We hit this when the driver is using a host wide
+		 * tag map. For device level tag maps the queue_depth check
+		 * in the device ready fn would prevent us from trying
+		 * to allocate a tag. Since the map is a shared host resource
+		 * we add the dev to the starved list so it eventually gets
+		 * a run when a tag is freed.
+		 */
+		if (blk_queue_tagged(q) && !blk_rq_tagged(req)) {
+			if (list_empty(&sdev->starved_entry))
+				list_add_tail(&sdev->starved_entry,
+					      &shost->starved_list);
+			goto not_ready;
+		}
+
 		if (!scsi_host_queue_ready(q, shost, sdev))
 		if (!scsi_host_queue_ready(q, shost, sdev))
 			goto not_ready;
 			goto not_ready;
 		if (scsi_target(sdev)->single_lun) {
 		if (scsi_target(sdev)->single_lun) {
@@ -2486,7 +2529,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
 	if (unlikely(i == sg_count)) {
 	if (unlikely(i == sg_count)) {
 		printk(KERN_ERR "%s: Bytes in sg: %zu, requested offset %zu, "
 		printk(KERN_ERR "%s: Bytes in sg: %zu, requested offset %zu, "
 			"elements %d\n",
 			"elements %d\n",
-		       __FUNCTION__, sg_len, *offset, sg_count);
+		       __func__, sg_len, *offset, sg_count);
 		WARN_ON(1);
 		WARN_ON(1);
 		return NULL;
 		return NULL;
 	}
 	}

+ 4 - 4
drivers/scsi/scsi_netlink.c

@@ -55,7 +55,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
 		if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
 		if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
 		    (skb->len < nlh->nlmsg_len)) {
 		    (skb->len < nlh->nlmsg_len)) {
 			printk(KERN_WARNING "%s: discarding partial skb\n",
 			printk(KERN_WARNING "%s: discarding partial skb\n",
-				 __FUNCTION__);
+				 __func__);
 			return;
 			return;
 		}
 		}
 
 
@@ -82,7 +82,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
 
 
 		if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
 		if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
 			printk(KERN_WARNING "%s: discarding partial message\n",
 			printk(KERN_WARNING "%s: discarding partial message\n",
-				 __FUNCTION__);
+				 __func__);
 			return;
 			return;
 		}
 		}
 
 
@@ -139,7 +139,7 @@ scsi_netlink_init(void)
 	error = netlink_register_notifier(&scsi_netlink_notifier);
 	error = netlink_register_notifier(&scsi_netlink_notifier);
 	if (error) {
 	if (error) {
 		printk(KERN_ERR "%s: register of event handler failed - %d\n",
 		printk(KERN_ERR "%s: register of event handler failed - %d\n",
-				__FUNCTION__, error);
+				__func__, error);
 		return;
 		return;
 	}
 	}
 
 
@@ -148,7 +148,7 @@ scsi_netlink_init(void)
 				THIS_MODULE);
 				THIS_MODULE);
 	if (!scsi_nl_sock) {
 	if (!scsi_nl_sock) {
 		printk(KERN_ERR "%s: register of recieve handler failed\n",
 		printk(KERN_ERR "%s: register of recieve handler failed\n",
-				__FUNCTION__);
+				__func__);
 		netlink_unregister_notifier(&scsi_netlink_notifier);
 		netlink_unregister_notifier(&scsi_netlink_notifier);
 	}
 	}
 
 

+ 1 - 0
drivers/scsi/scsi_priv.h

@@ -77,6 +77,7 @@ extern void scsi_exit_queue(void);
 struct request_queue;
 struct request_queue;
 struct request;
 struct request;
 extern int scsi_prep_fn(struct request_queue *, struct request *);
 extern int scsi_prep_fn(struct request_queue *, struct request *);
+extern struct kmem_cache *scsi_sdb_cache;
 
 
 /* scsi_proc.c */
 /* scsi_proc.c */
 #ifdef CONFIG_SCSI_PROC_FS
 #ifdef CONFIG_SCSI_PROC_FS

+ 2 - 2
drivers/scsi/scsi_proc.c

@@ -114,7 +114,7 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
 		sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
 		sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
         	if (!sht->proc_dir)
         	if (!sht->proc_dir)
 			printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
 			printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
-			       __FUNCTION__, sht->proc_name);
+			       __func__, sht->proc_name);
 		else
 		else
 			sht->proc_dir->owner = sht->module;
 			sht->proc_dir->owner = sht->module;
 	}
 	}
@@ -157,7 +157,7 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
 			sht->proc_dir, proc_scsi_read, shost);
 			sht->proc_dir, proc_scsi_read, shost);
 	if (!p) {
 	if (!p) {
 		printk(KERN_ERR "%s: Failed to register host %d in"
 		printk(KERN_ERR "%s: Failed to register host %d in"
-		       "%s\n", __FUNCTION__, shost->host_no,
+		       "%s\n", __func__, shost->host_no,
 		       sht->proc_name);
 		       sht->proc_name);
 		return;
 		return;
 	} 
 	} 

+ 7 - 6
drivers/scsi/scsi_scan.c

@@ -318,7 +318,7 @@ out_device_destroy:
 	put_device(&sdev->sdev_gendev);
 	put_device(&sdev->sdev_gendev);
 out:
 out:
 	if (display_failure_msg)
 	if (display_failure_msg)
-		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+		printk(ALLOC_FAILURE_MSG, __func__);
 	return NULL;
 	return NULL;
 }
 }
 
 
@@ -404,7 +404,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
 
 
 	starget = kzalloc(size, GFP_KERNEL);
 	starget = kzalloc(size, GFP_KERNEL);
 	if (!starget) {
 	if (!starget) {
-		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+		printk(KERN_ERR "%s: allocation failure\n", __func__);
 		return NULL;
 		return NULL;
 	}
 	}
 	dev = &starget->dev;
 	dev = &starget->dev;
@@ -1337,7 +1337,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
 	lun_data = kmalloc(length, GFP_ATOMIC |
 	lun_data = kmalloc(length, GFP_ATOMIC |
 			   (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
 			   (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
 	if (!lun_data) {
 	if (!lun_data) {
-		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+		printk(ALLOC_FAILURE_MSG, __func__);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -1649,7 +1649,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
 {
 {
 	SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost,
 	SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost,
 		"%s: <%u:%u:%u>\n",
 		"%s: <%u:%u:%u>\n",
-		__FUNCTION__, channel, id, lun));
+		__func__, channel, id, lun));
 
 
 	if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
 	if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
 	    ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
 	    ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
@@ -1703,7 +1703,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
 		return NULL;
 		return NULL;
 
 
 	if (shost->async_scan) {
 	if (shost->async_scan) {
-		printk("%s called twice for host %d", __FUNCTION__,
+		printk("%s called twice for host %d", __func__,
 				shost->host_no);
 				shost->host_no);
 		dump_stack();
 		dump_stack();
 		return NULL;
 		return NULL;
@@ -1757,9 +1757,10 @@ static void scsi_finish_async_scan(struct async_scan_data *data)
 	mutex_lock(&shost->scan_mutex);
 	mutex_lock(&shost->scan_mutex);
 
 
 	if (!shost->async_scan) {
 	if (!shost->async_scan) {
-		printk("%s called twice for host %d", __FUNCTION__,
+		printk("%s called twice for host %d", __func__,
 				shost->host_no);
 				shost->host_no);
 		dump_stack();
 		dump_stack();
+		mutex_unlock(&shost->scan_mutex);
 		return;
 		return;
 	}
 	}
 
 

+ 4 - 0
drivers/scsi/scsi_sysfs.c

@@ -249,6 +249,8 @@ shost_rd_attr(cmd_per_lun, "%hd\n");
 shost_rd_attr(can_queue, "%hd\n");
 shost_rd_attr(can_queue, "%hd\n");
 shost_rd_attr(sg_tablesize, "%hu\n");
 shost_rd_attr(sg_tablesize, "%hu\n");
 shost_rd_attr(unchecked_isa_dma, "%d\n");
 shost_rd_attr(unchecked_isa_dma, "%d\n");
+shost_rd_attr(prot_capabilities, "%u\n");
+shost_rd_attr(prot_guard_type, "%hd\n");
 shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
 shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
 
 
 static struct attribute *scsi_sysfs_shost_attrs[] = {
 static struct attribute *scsi_sysfs_shost_attrs[] = {
@@ -263,6 +265,8 @@ static struct attribute *scsi_sysfs_shost_attrs[] = {
 	&dev_attr_hstate.attr,
 	&dev_attr_hstate.attr,
 	&dev_attr_supported_mode.attr,
 	&dev_attr_supported_mode.attr,
 	&dev_attr_active_mode.attr,
 	&dev_attr_active_mode.attr,
+	&dev_attr_prot_capabilities.attr,
+	&dev_attr_prot_guard_type.attr,
 	NULL
 	NULL
 };
 };
 
 

+ 1 - 1
drivers/scsi/scsi_tgt_priv.h

@@ -6,7 +6,7 @@ struct task_struct;
 /* tmp - will replace with SCSI logging stuff */
 /* tmp - will replace with SCSI logging stuff */
 #define eprintk(fmt, args...)					\
 #define eprintk(fmt, args...)					\
 do {								\
 do {								\
-	printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);	\
+	printk("%s(%d) " fmt, __func__, __LINE__, ##args);	\
 } while (0)
 } while (0)
 
 
 #define dprintk(fmt, args...)
 #define dprintk(fmt, args...)

+ 6 - 6
drivers/scsi/scsi_transport_fc.c

@@ -571,7 +571,7 @@ send_fail:
 	name = get_fc_host_event_code_name(event_code);
 	name = get_fc_host_event_code_name(event_code);
 	printk(KERN_WARNING
 	printk(KERN_WARNING
 		"%s: Dropped Event : host %d %s data 0x%08x - err %d\n",
 		"%s: Dropped Event : host %d %s data 0x%08x - err %d\n",
-		__FUNCTION__, shost->host_no,
+		__func__, shost->host_no,
 		(name) ? name : "<unknown>", event_data, err);
 		(name) ? name : "<unknown>", event_data, err);
 	return;
 	return;
 }
 }
@@ -644,7 +644,7 @@ send_vendor_fail_skb:
 send_vendor_fail:
 send_vendor_fail:
 	printk(KERN_WARNING
 	printk(KERN_WARNING
 		"%s: Dropped Event : host %d vendor_unique - err %d\n",
 		"%s: Dropped Event : host %d vendor_unique - err %d\n",
-		__FUNCTION__, shost->host_no, err);
+		__func__, shost->host_no, err);
 	return;
 	return;
 }
 }
 EXPORT_SYMBOL(fc_host_post_vendor_event);
 EXPORT_SYMBOL(fc_host_post_vendor_event);
@@ -2464,7 +2464,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
 	size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size);
 	size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size);
 	rport = kzalloc(size, GFP_KERNEL);
 	rport = kzalloc(size, GFP_KERNEL);
 	if (unlikely(!rport)) {
 	if (unlikely(!rport)) {
-		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+		printk(KERN_ERR "%s: allocation failure\n", __func__);
 		return NULL;
 		return NULL;
 	}
 	}
 
 
@@ -3137,7 +3137,7 @@ fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
 	size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size);
 	size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size);
 	vport = kzalloc(size, GFP_KERNEL);
 	vport = kzalloc(size, GFP_KERNEL);
 	if (unlikely(!vport)) {
 	if (unlikely(!vport)) {
-		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+		printk(KERN_ERR "%s: allocation failure\n", __func__);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
@@ -3201,7 +3201,7 @@ fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
 			printk(KERN_ERR
 			printk(KERN_ERR
 				"%s: Cannot create vport symlinks for "
 				"%s: Cannot create vport symlinks for "
 				"%s, err=%d\n",
 				"%s, err=%d\n",
-				__FUNCTION__, dev->bus_id, error);
+				__func__, dev->bus_id, error);
 	}
 	}
 	spin_lock_irqsave(shost->host_lock, flags);
 	spin_lock_irqsave(shost->host_lock, flags);
 	vport->flags &= ~FC_VPORT_CREATING;
 	vport->flags &= ~FC_VPORT_CREATING;
@@ -3314,7 +3314,7 @@ fc_vport_sched_delete(struct work_struct *work)
 	if (stat)
 	if (stat)
 		dev_printk(KERN_ERR, vport->dev.parent,
 		dev_printk(KERN_ERR, vport->dev.parent,
 			"%s: %s could not be deleted created via "
 			"%s: %s could not be deleted created via "
-			"shost%d channel %d - error %d\n", __FUNCTION__,
+			"shost%d channel %d - error %d\n", __func__,
 			vport->dev.bus_id, vport->shost->host_no,
 			vport->dev.bus_id, vport->shost->host_no,
 			vport->channel, stat);
 			vport->channel, stat);
 }
 }

+ 2 - 2
drivers/scsi/scsi_transport_sas.c

@@ -779,7 +779,7 @@ static void sas_port_create_link(struct sas_port *port,
 	return;
 	return;
 err:
 err:
 	printk(KERN_ERR "%s: Cannot create port links, err=%d\n",
 	printk(KERN_ERR "%s: Cannot create port links, err=%d\n",
-	       __FUNCTION__, res);
+	       __func__, res);
 }
 }
 
 
 static void sas_port_delete_link(struct sas_port *port,
 static void sas_port_delete_link(struct sas_port *port,
@@ -1029,7 +1029,7 @@ void sas_port_mark_backlink(struct sas_port *port)
 	return;
 	return;
 err:
 err:
 	printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n",
 	printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n",
-	       __FUNCTION__, res);
+	       __func__, res);
 
 
 }
 }
 EXPORT_SYMBOL(sas_port_mark_backlink);
 EXPORT_SYMBOL(sas_port_mark_backlink);

+ 228 - 63
drivers/scsi/sd.c

@@ -99,8 +99,7 @@ static void scsi_disk_release(struct device *cdev);
 static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
 static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
 static void sd_print_result(struct scsi_disk *, int);
 static void sd_print_result(struct scsi_disk *, int);
 
 
-static DEFINE_IDR(sd_index_idr);
-static DEFINE_SPINLOCK(sd_index_lock);
+static DEFINE_IDA(sd_index_ida);
 
 
 /* This semaphore is used to mediate the 0->1 reference get in the
 /* This semaphore is used to mediate the 0->1 reference get in the
  * face of object destruction (i.e. we can't allow a get on an
  * face of object destruction (i.e. we can't allow a get on an
@@ -234,6 +233,24 @@ sd_show_allow_restart(struct device *dev, struct device_attribute *attr,
 	return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
 	return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
 }
 }
 
 
+static ssize_t
+sd_show_protection_type(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+	return snprintf(buf, 20, "%u\n", sdkp->protection_type);
+}
+
+static ssize_t
+sd_show_app_tag_own(struct device *dev, struct device_attribute *attr,
+		    char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+	return snprintf(buf, 20, "%u\n", sdkp->ATO);
+}
+
 static struct device_attribute sd_disk_attrs[] = {
 static struct device_attribute sd_disk_attrs[] = {
 	__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
 	__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
 	       sd_store_cache_type),
 	       sd_store_cache_type),
@@ -242,6 +259,8 @@ static struct device_attribute sd_disk_attrs[] = {
 	       sd_store_allow_restart),
 	       sd_store_allow_restart),
 	__ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
 	__ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
 	       sd_store_manage_start_stop),
 	       sd_store_manage_start_stop),
+	__ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL),
+	__ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
 	__ATTR_NULL,
 	__ATTR_NULL,
 };
 };
 
 
@@ -354,7 +373,9 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 	struct scsi_cmnd *SCpnt;
 	struct scsi_cmnd *SCpnt;
 	struct scsi_device *sdp = q->queuedata;
 	struct scsi_device *sdp = q->queuedata;
 	struct gendisk *disk = rq->rq_disk;
 	struct gendisk *disk = rq->rq_disk;
+	struct scsi_disk *sdkp;
 	sector_t block = rq->sector;
 	sector_t block = rq->sector;
+	sector_t threshold;
 	unsigned int this_count = rq->nr_sectors;
 	unsigned int this_count = rq->nr_sectors;
 	unsigned int timeout = sdp->timeout;
 	unsigned int timeout = sdp->timeout;
 	int ret;
 	int ret;
@@ -370,6 +391,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 	if (ret != BLKPREP_OK)
 	if (ret != BLKPREP_OK)
 		goto out;
 		goto out;
 	SCpnt = rq->special;
 	SCpnt = rq->special;
+	sdkp = scsi_disk(disk);
 
 
 	/* from here on until we're complete, any goto out
 	/* from here on until we're complete, any goto out
 	 * is used for a killable error condition */
 	 * is used for a killable error condition */
@@ -401,13 +423,21 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 	}
 	}
 
 
 	/*
 	/*
-	 * Some devices (some sdcards for one) don't like it if the
-	 * last sector gets read in a larger then 1 sector read.
+	 * Some SD card readers can't handle multi-sector accesses which touch
+	 * the last one or two hardware sectors.  Split accesses as needed.
 	 */
 	 */
-	if (unlikely(sdp->last_sector_bug &&
-	    rq->nr_sectors > sdp->sector_size / 512 &&
-	    block + this_count == get_capacity(disk)))
-		this_count -= sdp->sector_size / 512;
+	threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS *
+		(sdp->sector_size / 512);
+
+	if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) {
+		if (block < threshold) {
+			/* Access up to the threshold but not beyond */
+			this_count = threshold - block;
+		} else {
+			/* Access only a single hardware sector */
+			this_count = sdp->sector_size / 512;
+		}
+	}
 
 
 	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
 	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
 					(unsigned long long)block));
 					(unsigned long long)block));
@@ -459,6 +489,11 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 		}
 		}
 		SCpnt->cmnd[0] = WRITE_6;
 		SCpnt->cmnd[0] = WRITE_6;
 		SCpnt->sc_data_direction = DMA_TO_DEVICE;
 		SCpnt->sc_data_direction = DMA_TO_DEVICE;
+
+		if (blk_integrity_rq(rq) &&
+		    sd_dif_prepare(rq, block, sdp->sector_size) == -EIO)
+			goto out;
+
 	} else if (rq_data_dir(rq) == READ) {
 	} else if (rq_data_dir(rq) == READ) {
 		SCpnt->cmnd[0] = READ_6;
 		SCpnt->cmnd[0] = READ_6;
 		SCpnt->sc_data_direction = DMA_FROM_DEVICE;
 		SCpnt->sc_data_direction = DMA_FROM_DEVICE;
@@ -473,8 +508,12 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 					"writing" : "reading", this_count,
 					"writing" : "reading", this_count,
 					rq->nr_sectors));
 					rq->nr_sectors));
 
 
-	SCpnt->cmnd[1] = 0;
-	
+	/* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
+	if (scsi_host_dif_capable(sdp->host, sdkp->protection_type))
+		SCpnt->cmnd[1] = 1 << 5;
+	else
+		SCpnt->cmnd[1] = 0;
+
 	if (block > 0xffffffff) {
 	if (block > 0xffffffff) {
 		SCpnt->cmnd[0] += READ_16 - READ_6;
 		SCpnt->cmnd[0] += READ_16 - READ_6;
 		SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
 		SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
@@ -492,6 +531,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 		SCpnt->cmnd[13] = (unsigned char) this_count & 0xff;
 		SCpnt->cmnd[13] = (unsigned char) this_count & 0xff;
 		SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0;
 		SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0;
 	} else if ((this_count > 0xff) || (block > 0x1fffff) ||
 	} else if ((this_count > 0xff) || (block > 0x1fffff) ||
+		   scsi_device_protection(SCpnt->device) ||
 		   SCpnt->device->use_10_for_rw) {
 		   SCpnt->device->use_10_for_rw) {
 		if (this_count > 0xffff)
 		if (this_count > 0xffff)
 			this_count = 0xffff;
 			this_count = 0xffff;
@@ -526,6 +566,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 	}
 	}
 	SCpnt->sdb.length = this_count * sdp->sector_size;
 	SCpnt->sdb.length = this_count * sdp->sector_size;
 
 
+	/* If DIF or DIX is enabled, tell HBA how to handle request */
+	if (sdkp->protection_type || scsi_prot_sg_count(SCpnt))
+		sd_dif_op(SCpnt, sdkp->protection_type, scsi_prot_sg_count(SCpnt));
+
 	/*
 	/*
 	 * We shouldn't disconnect in the middle of a sector, so with a dumb
 	 * We shouldn't disconnect in the middle of a sector, so with a dumb
 	 * host adapter, it's safe to assume that we can at least transfer
 	 * host adapter, it's safe to assume that we can at least transfer
@@ -920,6 +964,48 @@ static struct block_device_operations sd_fops = {
 	.revalidate_disk	= sd_revalidate_disk,
 	.revalidate_disk	= sd_revalidate_disk,
 };
 };
 
 
+static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
+{
+	u64 start_lba = scmd->request->sector;
+	u64 end_lba = scmd->request->sector + (scsi_bufflen(scmd) / 512);
+	u64 bad_lba;
+	int info_valid;
+
+	if (!blk_fs_request(scmd->request))
+		return 0;
+
+	info_valid = scsi_get_sense_info_fld(scmd->sense_buffer,
+					     SCSI_SENSE_BUFFERSIZE,
+					     &bad_lba);
+	if (!info_valid)
+		return 0;
+
+	if (scsi_bufflen(scmd) <= scmd->device->sector_size)
+		return 0;
+
+	if (scmd->device->sector_size < 512) {
+		/* only legitimate sector_size here is 256 */
+		start_lba <<= 1;
+		end_lba <<= 1;
+	} else {
+		/* be careful ... don't want any overflows */
+		u64 factor = scmd->device->sector_size / 512;
+		do_div(start_lba, factor);
+		do_div(end_lba, factor);
+	}
+
+	/* The bad lba was reported incorrectly, we have no idea where
+	 * the error is.
+	 */
+	if (bad_lba < start_lba  || bad_lba >= end_lba)
+		return 0;
+
+	/* This computation should always be done in terms of
+	 * the resolution of the device's medium.
+	 */
+	return (bad_lba - start_lba) * scmd->device->sector_size;
+}
+
 /**
 /**
  *	sd_done - bottom half handler: called when the lower level
  *	sd_done - bottom half handler: called when the lower level
  *	driver has completed (successfully or otherwise) a scsi command.
  *	driver has completed (successfully or otherwise) a scsi command.
@@ -930,15 +1016,10 @@ static struct block_device_operations sd_fops = {
 static int sd_done(struct scsi_cmnd *SCpnt)
 static int sd_done(struct scsi_cmnd *SCpnt)
 {
 {
 	int result = SCpnt->result;
 	int result = SCpnt->result;
-	unsigned int xfer_size = scsi_bufflen(SCpnt);
- 	unsigned int good_bytes = result ? 0 : xfer_size;
- 	u64 start_lba = SCpnt->request->sector;
-	u64 end_lba = SCpnt->request->sector + (xfer_size / 512);
- 	u64 bad_lba;
+	unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt);
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
 	int sense_valid = 0;
 	int sense_valid = 0;
 	int sense_deferred = 0;
 	int sense_deferred = 0;
-	int info_valid;
 
 
 	if (result) {
 	if (result) {
 		sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
 		sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
@@ -963,36 +1044,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)
 	switch (sshdr.sense_key) {
 	switch (sshdr.sense_key) {
 	case HARDWARE_ERROR:
 	case HARDWARE_ERROR:
 	case MEDIUM_ERROR:
 	case MEDIUM_ERROR:
-		if (!blk_fs_request(SCpnt->request))
-			goto out;
-		info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer,
-						     SCSI_SENSE_BUFFERSIZE,
-						     &bad_lba);
-		if (!info_valid)
-			goto out;
-		if (xfer_size <= SCpnt->device->sector_size)
-			goto out;
-		if (SCpnt->device->sector_size < 512) {
-			/* only legitimate sector_size here is 256 */
-			start_lba <<= 1;
-			end_lba <<= 1;
-		} else {
-			/* be careful ... don't want any overflows */
-			u64 factor = SCpnt->device->sector_size / 512;
-			do_div(start_lba, factor);
-			do_div(end_lba, factor);
-		}
-
-		if (bad_lba < start_lba  || bad_lba >= end_lba)
-			/* the bad lba was reported incorrectly, we have
-			 * no idea where the error is
-			 */
-			goto out;
-
-		/* This computation should always be done in terms of
-		 * the resolution of the device's medium.
-		 */
-		good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size;
+		good_bytes = sd_completed_bytes(SCpnt);
 		break;
 		break;
 	case RECOVERED_ERROR:
 	case RECOVERED_ERROR:
 	case NO_SENSE:
 	case NO_SENSE:
@@ -1002,10 +1054,23 @@ static int sd_done(struct scsi_cmnd *SCpnt)
 		scsi_print_sense("sd", SCpnt);
 		scsi_print_sense("sd", SCpnt);
 		SCpnt->result = 0;
 		SCpnt->result = 0;
 		memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 		memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-		good_bytes = xfer_size;
+		good_bytes = scsi_bufflen(SCpnt);
+		break;
+	case ABORTED_COMMAND:
+		if (sshdr.asc == 0x10) { /* DIF: Disk detected corruption */
+			scsi_print_result(SCpnt);
+			scsi_print_sense("sd", SCpnt);
+			good_bytes = sd_completed_bytes(SCpnt);
+		}
 		break;
 		break;
 	case ILLEGAL_REQUEST:
 	case ILLEGAL_REQUEST:
-		if (SCpnt->device->use_10_for_rw &&
+		if (sshdr.asc == 0x10) { /* DIX: HBA detected corruption */
+			scsi_print_result(SCpnt);
+			scsi_print_sense("sd", SCpnt);
+			good_bytes = sd_completed_bytes(SCpnt);
+		}
+		if (!scsi_device_protection(SCpnt->device) &&
+		    SCpnt->device->use_10_for_rw &&
 		    (SCpnt->cmnd[0] == READ_10 ||
 		    (SCpnt->cmnd[0] == READ_10 ||
 		     SCpnt->cmnd[0] == WRITE_10))
 		     SCpnt->cmnd[0] == WRITE_10))
 			SCpnt->device->use_10_for_rw = 0;
 			SCpnt->device->use_10_for_rw = 0;
@@ -1018,6 +1083,9 @@ static int sd_done(struct scsi_cmnd *SCpnt)
 		break;
 		break;
 	}
 	}
  out:
  out:
+	if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
+		sd_dif_complete(SCpnt, good_bytes);
+
 	return good_bytes;
 	return good_bytes;
 }
 }
 
 
@@ -1165,6 +1233,49 @@ sd_spinup_disk(struct scsi_disk *sdkp)
 	}
 	}
 }
 }
 
 
+
+/*
+ * Determine whether disk supports Data Integrity Field.
+ */
+void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
+{
+	struct scsi_device *sdp = sdkp->device;
+	u8 type;
+
+	if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0)
+		type = 0;
+	else
+		type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
+
+	switch (type) {
+	case SD_DIF_TYPE0_PROTECTION:
+		sdkp->protection_type = 0;
+		break;
+
+	case SD_DIF_TYPE1_PROTECTION:
+	case SD_DIF_TYPE3_PROTECTION:
+		sdkp->protection_type = type;
+		break;
+
+	case SD_DIF_TYPE2_PROTECTION:
+		sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 "	\
+			  "protection which is currently unsupported. "	\
+			  "Disabling disk!\n");
+		goto disable;
+
+	default:
+		sd_printk(KERN_ERR, sdkp, "formatted with unknown "	\
+			  "protection type %d. Disabling disk!\n", type);
+		goto disable;
+	}
+
+	return;
+
+disable:
+	sdkp->protection_type = 0;
+	sdkp->capacity = 0;
+}
+
 /*
 /*
  * read disk capacity
  * read disk capacity
  */
  */
@@ -1174,7 +1285,8 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
 	unsigned char cmd[16];
 	unsigned char cmd[16];
 	int the_result, retries;
 	int the_result, retries;
 	int sector_size = 0;
 	int sector_size = 0;
-	int longrc = 0;
+	/* Force READ CAPACITY(16) when PROTECT=1 */
+	int longrc = scsi_device_protection(sdkp->device) ? 1 : 0;
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
 	int sense_valid = 0;
 	int sense_valid = 0;
 	struct scsi_device *sdp = sdkp->device;
 	struct scsi_device *sdp = sdkp->device;
@@ -1186,8 +1298,8 @@ repeat:
 			memset((void *) cmd, 0, 16);
 			memset((void *) cmd, 0, 16);
 			cmd[0] = SERVICE_ACTION_IN;
 			cmd[0] = SERVICE_ACTION_IN;
 			cmd[1] = SAI_READ_CAPACITY_16;
 			cmd[1] = SAI_READ_CAPACITY_16;
-			cmd[13] = 12;
-			memset((void *) buffer, 0, 12);
+			cmd[13] = 13;
+			memset((void *) buffer, 0, 13);
 		} else {
 		} else {
 			cmd[0] = READ_CAPACITY;
 			cmd[0] = READ_CAPACITY;
 			memset((void *) &cmd[1], 0, 9);
 			memset((void *) &cmd[1], 0, 9);
@@ -1195,7 +1307,7 @@ repeat:
 		}
 		}
 		
 		
 		the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
 		the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
-					      buffer, longrc ? 12 : 8, &sshdr,
+					      buffer, longrc ? 13 : 8, &sshdr,
 					      SD_TIMEOUT, SD_MAX_RETRIES);
 					      SD_TIMEOUT, SD_MAX_RETRIES);
 
 
 		if (media_not_present(sdkp, &sshdr))
 		if (media_not_present(sdkp, &sshdr))
@@ -1270,6 +1382,8 @@ repeat:
 			
 			
 		sector_size = (buffer[8] << 24) |
 		sector_size = (buffer[8] << 24) |
 			(buffer[9] << 16) | (buffer[10] << 8) | buffer[11];
 			(buffer[9] << 16) | (buffer[10] << 8) | buffer[11];
+
+		sd_read_protection_type(sdkp, buffer);
 	}	
 	}	
 
 
 	/* Some devices return the total number of sectors, not the
 	/* Some devices return the total number of sectors, not the
@@ -1531,6 +1645,52 @@ defaults:
 	sdkp->DPOFUA = 0;
 	sdkp->DPOFUA = 0;
 }
 }
 
 
+/*
+ * The ATO bit indicates whether the DIF application tag is available
+ * for use by the operating system.
+ */
+void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
+{
+	int res, offset;
+	struct scsi_device *sdp = sdkp->device;
+	struct scsi_mode_data data;
+	struct scsi_sense_hdr sshdr;
+
+	if (sdp->type != TYPE_DISK)
+		return;
+
+	if (sdkp->protection_type == 0)
+		return;
+
+	res = scsi_mode_sense(sdp, 1, 0x0a, buffer, 36, SD_TIMEOUT,
+			      SD_MAX_RETRIES, &data, &sshdr);
+
+	if (!scsi_status_is_good(res) || !data.header_length ||
+	    data.length < 6) {
+		sd_printk(KERN_WARNING, sdkp,
+			  "getting Control mode page failed, assume no ATO\n");
+
+		if (scsi_sense_valid(&sshdr))
+			sd_print_sense_hdr(sdkp, &sshdr);
+
+		return;
+	}
+
+	offset = data.header_length + data.block_descriptor_length;
+
+	if ((buffer[offset] & 0x3f) != 0x0a) {
+		sd_printk(KERN_ERR, sdkp, "ATO Got wrong page\n");
+		return;
+	}
+
+	if ((buffer[offset + 5] & 0x80) == 0)
+		return;
+
+	sdkp->ATO = 1;
+
+	return;
+}
+
 /**
 /**
  *	sd_revalidate_disk - called the first time a new disk is seen,
  *	sd_revalidate_disk - called the first time a new disk is seen,
  *	performs disk spin up, read_capacity, etc.
  *	performs disk spin up, read_capacity, etc.
@@ -1567,6 +1727,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
 	sdkp->write_prot = 0;
 	sdkp->write_prot = 0;
 	sdkp->WCE = 0;
 	sdkp->WCE = 0;
 	sdkp->RCD = 0;
 	sdkp->RCD = 0;
+	sdkp->ATO = 0;
 
 
 	sd_spinup_disk(sdkp);
 	sd_spinup_disk(sdkp);
 
 
@@ -1578,6 +1739,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
 		sd_read_capacity(sdkp, buffer);
 		sd_read_capacity(sdkp, buffer);
 		sd_read_write_protect_flag(sdkp, buffer);
 		sd_read_write_protect_flag(sdkp, buffer);
 		sd_read_cache_type(sdkp, buffer);
 		sd_read_cache_type(sdkp, buffer);
+		sd_read_app_tag_own(sdkp, buffer);
 	}
 	}
 
 
 	/*
 	/*
@@ -1643,18 +1805,20 @@ static int sd_probe(struct device *dev)
 	if (!gd)
 	if (!gd)
 		goto out_free;
 		goto out_free;
 
 
-	if (!idr_pre_get(&sd_index_idr, GFP_KERNEL))
-		goto out_put;
+	do {
+		if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
+			goto out_put;
 
 
-	spin_lock(&sd_index_lock);
-	error = idr_get_new(&sd_index_idr, NULL, &index);
-	spin_unlock(&sd_index_lock);
+		error = ida_get_new(&sd_index_ida, &index);
+	} while (error == -EAGAIN);
 
 
-	if (index >= SD_MAX_DISKS)
-		error = -EBUSY;
 	if (error)
 	if (error)
 		goto out_put;
 		goto out_put;
 
 
+	error = -EBUSY;
+	if (index >= SD_MAX_DISKS)
+		goto out_free_index;
+
 	sdkp->device = sdp;
 	sdkp->device = sdp;
 	sdkp->driver = &sd_template;
 	sdkp->driver = &sd_template;
 	sdkp->disk = gd;
 	sdkp->disk = gd;
@@ -1675,7 +1839,7 @@ static int sd_probe(struct device *dev)
 	strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
 	strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
 
 
 	if (device_add(&sdkp->dev))
 	if (device_add(&sdkp->dev))
-		goto out_put;
+		goto out_free_index;
 
 
 	get_device(&sdp->sdev_gendev);
 	get_device(&sdp->sdev_gendev);
 
 
@@ -1711,12 +1875,15 @@ static int sd_probe(struct device *dev)
 
 
 	dev_set_drvdata(dev, sdkp);
 	dev_set_drvdata(dev, sdkp);
 	add_disk(gd);
 	add_disk(gd);
+	sd_dif_config_host(sdkp);
 
 
 	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
 	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
 		  sdp->removable ? "removable " : "");
 		  sdp->removable ? "removable " : "");
 
 
 	return 0;
 	return 0;
 
 
+ out_free_index:
+	ida_remove(&sd_index_ida, index);
  out_put:
  out_put:
 	put_disk(gd);
 	put_disk(gd);
  out_free:
  out_free:
@@ -1766,9 +1933,7 @@ static void scsi_disk_release(struct device *dev)
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct gendisk *disk = sdkp->disk;
 	struct gendisk *disk = sdkp->disk;
 	
 	
-	spin_lock(&sd_index_lock);
-	idr_remove(&sd_index_idr, sdkp->index);
-	spin_unlock(&sd_index_lock);
+	ida_remove(&sd_index_ida, sdkp->index);
 
 
 	disk->private_data = NULL;
 	disk->private_data = NULL;
 	put_disk(disk);
 	put_disk(disk);

+ 54 - 0
drivers/scsi/sd.h

@@ -31,6 +31,12 @@
  */
  */
 #define SD_BUF_SIZE		512
 #define SD_BUF_SIZE		512
 
 
+/*
+ * Number of sectors at the end of the device to avoid multi-sector
+ * accesses to in the case of last_sector_bug
+ */
+#define SD_LAST_BUGGY_SECTORS	8
+
 struct scsi_disk {
 struct scsi_disk {
 	struct scsi_driver *driver;	/* always &sd_template */
 	struct scsi_driver *driver;	/* always &sd_template */
 	struct scsi_device *device;
 	struct scsi_device *device;
@@ -41,7 +47,9 @@ struct scsi_disk {
 	u32		index;
 	u32		index;
 	u8		media_present;
 	u8		media_present;
 	u8		write_prot;
 	u8		write_prot;
+	u8		protection_type;/* Data Integrity Field */
 	unsigned	previous_state : 1;
 	unsigned	previous_state : 1;
+	unsigned	ATO : 1;	/* state of disk ATO bit */
 	unsigned	WCE : 1;	/* state of disk WCE bit */
 	unsigned	WCE : 1;	/* state of disk WCE bit */
 	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
 	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
 	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
 	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
@@ -59,4 +67,50 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
 		    (sdsk)->disk->disk_name, ##a) :			\
 		    (sdsk)->disk->disk_name, ##a) :			\
 	sdev_printk(prefix, (sdsk)->device, fmt, ##a)
 	sdev_printk(prefix, (sdsk)->device, fmt, ##a)
 
 
+/*
+ * A DIF-capable target device can be formatted with different
+ * protection schemes.  Currently 0 through 3 are defined:
+ *
+ * Type 0 is regular (unprotected) I/O
+ *
+ * Type 1 defines the contents of the guard and reference tags
+ *
+ * Type 2 defines the contents of the guard and reference tags and
+ * uses 32-byte commands to seed the latter
+ *
+ * Type 3 defines the contents of the guard tag only
+ */
+
+enum sd_dif_target_protection_types {
+	SD_DIF_TYPE0_PROTECTION = 0x0,
+	SD_DIF_TYPE1_PROTECTION = 0x1,
+	SD_DIF_TYPE2_PROTECTION = 0x2,
+	SD_DIF_TYPE3_PROTECTION = 0x3,
+};
+
+/*
+ * Data Integrity Field tuple.
+ */
+struct sd_dif_tuple {
+       __be16 guard_tag;	/* Checksum */
+       __be16 app_tag;		/* Opaque storage */
+       __be32 ref_tag;		/* Target LBA or indirect LBA */
+};
+
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+
+extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int);
+extern void sd_dif_config_host(struct scsi_disk *);
+extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int);
+extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
+
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+
+#define sd_dif_op(a, b, c)			do { } while (0)
+#define sd_dif_config_host(a)			do { } while (0)
+#define sd_dif_prepare(a, b, c)			(0)
+#define sd_dif_complete(a, b)			(0)
+
+#endif /* CONFIG_BLK_DEV_INTEGRITY */
+
 #endif /* _SCSI_DISK_H */
 #endif /* _SCSI_DISK_H */

+ 538 - 0
drivers/scsi/sd_dif.c

@@ -0,0 +1,538 @@
+/*
+ * sd_dif.c - SCSI Data Integrity Field
+ *
+ * Copyright (C) 2007, 2008 Oracle Corporation
+ * Written by: Martin K. Petersen <martin.petersen@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ */
+
+#include <linux/blkdev.h>
+#include <linux/crc-t10dif.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsicam.h>
+
+#include <net/checksum.h>
+
+#include "sd.h"
+
+typedef __u16 (csum_fn) (void *, unsigned int);
+
+static __u16 sd_dif_crc_fn(void *data, unsigned int len)
+{
+	return cpu_to_be16(crc_t10dif(data, len));
+}
+
+static __u16 sd_dif_ip_fn(void *data, unsigned int len)
+{
+	return ip_compute_csum(data, len);
+}
+
+/*
+ * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
+ * 16 bit app tag, 32 bit reference tag.
+ */
+static void sd_dif_type1_generate(struct blk_integrity_exchg *bix, csum_fn *fn)
+{
+	void *buf = bix->data_buf;
+	struct sd_dif_tuple *sdt = bix->prot_buf;
+	sector_t sector = bix->sector;
+	unsigned int i;
+
+	for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
+		sdt->guard_tag = fn(buf, bix->sector_size);
+		sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
+		sdt->app_tag = 0;
+
+		buf += bix->sector_size;
+		sector++;
+	}
+}
+
+static void sd_dif_type1_generate_crc(struct blk_integrity_exchg *bix)
+{
+	sd_dif_type1_generate(bix, sd_dif_crc_fn);
+}
+
+static void sd_dif_type1_generate_ip(struct blk_integrity_exchg *bix)
+{
+	sd_dif_type1_generate(bix, sd_dif_ip_fn);
+}
+
+static int sd_dif_type1_verify(struct blk_integrity_exchg *bix, csum_fn *fn)
+{
+	void *buf = bix->data_buf;
+	struct sd_dif_tuple *sdt = bix->prot_buf;
+	sector_t sector = bix->sector;
+	unsigned int i;
+	__u16 csum;
+
+	for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
+		/* Unwritten sectors */
+		if (sdt->app_tag == 0xffff)
+			return 0;
+
+		/* Bad ref tag received from disk */
+		if (sdt->ref_tag == 0xffffffff) {
+			printk(KERN_ERR
+			       "%s: bad phys ref tag on sector %lu\n",
+			       bix->disk_name, (unsigned long)sector);
+			return -EIO;
+		}
+
+		if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
+			printk(KERN_ERR
+			       "%s: ref tag error on sector %lu (rcvd %u)\n",
+			       bix->disk_name, (unsigned long)sector,
+			       be32_to_cpu(sdt->ref_tag));
+			return -EIO;
+		}
+
+		csum = fn(buf, bix->sector_size);
+
+		if (sdt->guard_tag != csum) {
+			printk(KERN_ERR "%s: guard tag error on sector %lu " \
+			       "(rcvd %04x, data %04x)\n", bix->disk_name,
+			       (unsigned long)sector,
+			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
+			return -EIO;
+		}
+
+		buf += bix->sector_size;
+		sector++;
+	}
+
+	return 0;
+}
+
+static int sd_dif_type1_verify_crc(struct blk_integrity_exchg *bix)
+{
+	return sd_dif_type1_verify(bix, sd_dif_crc_fn);
+}
+
+static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix)
+{
+	return sd_dif_type1_verify(bix, sd_dif_ip_fn);
+}
+
+/*
+ * Functions for interleaving and deinterleaving application tags
+ */
+static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors)
+{
+	struct sd_dif_tuple *sdt = prot;
+	char *tag = tag_buf;
+	unsigned int i, j;
+
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
+		sdt->app_tag = tag[j] << 8 | tag[j+1];
+		BUG_ON(sdt->app_tag == 0xffff);
+	}
+}
+
+static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors)
+{
+	struct sd_dif_tuple *sdt = prot;
+	char *tag = tag_buf;
+	unsigned int i, j;
+
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
+		tag[j] = (sdt->app_tag & 0xff00) >> 8;
+		tag[j+1] = sdt->app_tag & 0xff;
+	}
+}
+
+static struct blk_integrity dif_type1_integrity_crc = {
+	.name			= "T10-DIF-TYPE1-CRC",
+	.generate_fn		= sd_dif_type1_generate_crc,
+	.verify_fn		= sd_dif_type1_verify_crc,
+	.get_tag_fn		= sd_dif_type1_get_tag,
+	.set_tag_fn		= sd_dif_type1_set_tag,
+	.tuple_size		= sizeof(struct sd_dif_tuple),
+	.tag_size		= 0,
+};
+
+static struct blk_integrity dif_type1_integrity_ip = {
+	.name			= "T10-DIF-TYPE1-IP",
+	.generate_fn		= sd_dif_type1_generate_ip,
+	.verify_fn		= sd_dif_type1_verify_ip,
+	.get_tag_fn		= sd_dif_type1_get_tag,
+	.set_tag_fn		= sd_dif_type1_set_tag,
+	.tuple_size		= sizeof(struct sd_dif_tuple),
+	.tag_size		= 0,
+};
+
+
+/*
+ * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
+ * tag space.
+ */
+static void sd_dif_type3_generate(struct blk_integrity_exchg *bix, csum_fn *fn)
+{
+	void *buf = bix->data_buf;
+	struct sd_dif_tuple *sdt = bix->prot_buf;
+	unsigned int i;
+
+	for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
+		sdt->guard_tag = fn(buf, bix->sector_size);
+		sdt->ref_tag = 0;
+		sdt->app_tag = 0;
+
+		buf += bix->sector_size;
+	}
+}
+
+static void sd_dif_type3_generate_crc(struct blk_integrity_exchg *bix)
+{
+	sd_dif_type3_generate(bix, sd_dif_crc_fn);
+}
+
+static void sd_dif_type3_generate_ip(struct blk_integrity_exchg *bix)
+{
+	sd_dif_type3_generate(bix, sd_dif_ip_fn);
+}
+
+static int sd_dif_type3_verify(struct blk_integrity_exchg *bix, csum_fn *fn)
+{
+	void *buf = bix->data_buf;
+	struct sd_dif_tuple *sdt = bix->prot_buf;
+	sector_t sector = bix->sector;
+	unsigned int i;
+	__u16 csum;
+
+	for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
+		/* Unwritten sectors */
+		if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff)
+			return 0;
+
+		csum = fn(buf, bix->sector_size);
+
+		if (sdt->guard_tag != csum) {
+			printk(KERN_ERR "%s: guard tag error on sector %lu " \
+			       "(rcvd %04x, data %04x)\n", bix->disk_name,
+			       (unsigned long)sector,
+			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
+			return -EIO;
+		}
+
+		buf += bix->sector_size;
+		sector++;
+	}
+
+	return 0;
+}
+
+static int sd_dif_type3_verify_crc(struct blk_integrity_exchg *bix)
+{
+	return sd_dif_type3_verify(bix, sd_dif_crc_fn);
+}
+
+static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix)
+{
+	return sd_dif_type3_verify(bix, sd_dif_ip_fn);
+}
+
+static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors)
+{
+	struct sd_dif_tuple *sdt = prot;
+	char *tag = tag_buf;
+	unsigned int i, j;
+
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 6, sdt++) {
+		sdt->app_tag = tag[j] << 8 | tag[j+1];
+		sdt->ref_tag = tag[j+2] << 24 | tag[j+3] << 16 |
+			tag[j+4] << 8 | tag[j+5];
+	}
+}
+
+static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors)
+{
+	struct sd_dif_tuple *sdt = prot;
+	char *tag = tag_buf;
+	unsigned int i, j;
+
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
+		tag[j] = (sdt->app_tag & 0xff00) >> 8;
+		tag[j+1] = sdt->app_tag & 0xff;
+		tag[j+2] = (sdt->ref_tag & 0xff000000) >> 24;
+		tag[j+3] = (sdt->ref_tag & 0xff0000) >> 16;
+		tag[j+4] = (sdt->ref_tag & 0xff00) >> 8;
+		tag[j+5] = sdt->ref_tag & 0xff;
+		BUG_ON(sdt->app_tag == 0xffff || sdt->ref_tag == 0xffffffff);
+	}
+}
+
+static struct blk_integrity dif_type3_integrity_crc = {
+	.name			= "T10-DIF-TYPE3-CRC",
+	.generate_fn		= sd_dif_type3_generate_crc,
+	.verify_fn		= sd_dif_type3_verify_crc,
+	.get_tag_fn		= sd_dif_type3_get_tag,
+	.set_tag_fn		= sd_dif_type3_set_tag,
+	.tuple_size		= sizeof(struct sd_dif_tuple),
+	.tag_size		= 0,
+};
+
+static struct blk_integrity dif_type3_integrity_ip = {
+	.name			= "T10-DIF-TYPE3-IP",
+	.generate_fn		= sd_dif_type3_generate_ip,
+	.verify_fn		= sd_dif_type3_verify_ip,
+	.get_tag_fn		= sd_dif_type3_get_tag,
+	.set_tag_fn		= sd_dif_type3_set_tag,
+	.tuple_size		= sizeof(struct sd_dif_tuple),
+	.tag_size		= 0,
+};
+
+/*
+ * Configure exchange of protection information between OS and HBA.
+ */
+void sd_dif_config_host(struct scsi_disk *sdkp)
+{
+	struct scsi_device *sdp = sdkp->device;
+	struct gendisk *disk = sdkp->disk;
+	u8 type = sdkp->protection_type;
+
+	/* If this HBA doesn't support DIX, resort to normal I/O or DIF */
+	if (scsi_host_dix_capable(sdp->host, type) == 0) {
+
+		if (type == SD_DIF_TYPE0_PROTECTION)
+			return;
+
+		if (scsi_host_dif_capable(sdp->host, type) == 0) {
+			sd_printk(KERN_INFO, sdkp, "Type %d protection " \
+				  "unsupported by HBA. Disabling DIF.\n", type);
+			sdkp->protection_type = 0;
+			return;
+		}
+
+		sd_printk(KERN_INFO, sdkp, "Enabling DIF Type %d protection\n",
+			  type);
+
+		return;
+	}
+
+	/* Enable DMA of protection information */
+	if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP)
+		if (type == SD_DIF_TYPE3_PROTECTION)
+			blk_integrity_register(disk, &dif_type3_integrity_ip);
+		else
+			blk_integrity_register(disk, &dif_type1_integrity_ip);
+	else
+		if (type == SD_DIF_TYPE3_PROTECTION)
+			blk_integrity_register(disk, &dif_type3_integrity_crc);
+		else
+			blk_integrity_register(disk, &dif_type1_integrity_crc);
+
+	sd_printk(KERN_INFO, sdkp,
+		  "Enabling %s integrity protection\n", disk->integrity->name);
+
+	/* Signal to block layer that we support sector tagging */
+	if (type && sdkp->ATO) {
+		if (type == SD_DIF_TYPE3_PROTECTION)
+			disk->integrity->tag_size = sizeof(u16) + sizeof(u32);
+		else
+			disk->integrity->tag_size = sizeof(u16);
+
+		sd_printk(KERN_INFO, sdkp, "DIF application tag size %u\n",
+			  disk->integrity->tag_size);
+	}
+}
+
+/*
+ * DIF DMA operation magic decoder ring.
+ */
+void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix)
+{
+	int csum_convert, prot_op;
+
+	prot_op = 0;
+
+	/* Convert checksum? */
+	if (scsi_host_get_guard(scmd->device->host) != SHOST_DIX_GUARD_CRC)
+		csum_convert = 1;
+	else
+		csum_convert = 0;
+
+	switch (scmd->cmnd[0]) {
+	case READ_10:
+	case READ_12:
+	case READ_16:
+		if (dif && dix)
+			if (csum_convert)
+				prot_op = SCSI_PROT_READ_CONVERT;
+			else
+				prot_op = SCSI_PROT_READ_PASS;
+		else if (dif && !dix)
+			prot_op = SCSI_PROT_READ_STRIP;
+		else if (!dif && dix)
+			prot_op = SCSI_PROT_READ_INSERT;
+
+		break;
+
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_16:
+		if (dif && dix)
+			if (csum_convert)
+				prot_op = SCSI_PROT_WRITE_CONVERT;
+			else
+				prot_op = SCSI_PROT_WRITE_PASS;
+		else if (dif && !dix)
+			prot_op = SCSI_PROT_WRITE_INSERT;
+		else if (!dif && dix)
+			prot_op = SCSI_PROT_WRITE_STRIP;
+
+		break;
+	}
+
+	scsi_set_prot_op(scmd, prot_op);
+	scsi_set_prot_type(scmd, dif);
+}
+
+/*
+ * The virtual start sector is the one that was originally submitted
+ * by the block layer.	Due to partitioning, MD/DM cloning, etc. the
+ * actual physical start sector is likely to be different.  Remap
+ * protection information to match the physical LBA.
+ *
+ * From a protocol perspective there's a slight difference between
+ * Type 1 and 2.  The latter uses 32-byte CDBs exclusively, and the
+ * reference tag is seeded in the CDB.  This gives us the potential to
+ * avoid virt->phys remapping during write.  However, at read time we
+ * don't know whether the virt sector is the same as when we wrote it
+ * (we could be reading from real disk as opposed to MD/DM device.  So
+ * we always remap Type 2 making it identical to Type 1.
+ *
+ * Type 3 does not have a reference tag so no remapping is required.
+ */
+int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_sz)
+{
+	const int tuple_sz = sizeof(struct sd_dif_tuple);
+	struct bio *bio;
+	struct scsi_disk *sdkp;
+	struct sd_dif_tuple *sdt;
+	unsigned int i, j;
+	u32 phys, virt;
+
+	/* Already remapped? */
+	if (rq->cmd_flags & REQ_INTEGRITY)
+		return 0;
+
+	sdkp = rq->bio->bi_bdev->bd_disk->private_data;
+
+	if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION)
+		return 0;
+
+	rq->cmd_flags |= REQ_INTEGRITY;
+	phys = hw_sector & 0xffffffff;
+
+	__rq_for_each_bio(bio, rq) {
+		struct bio_vec *iv;
+
+		virt = bio->bi_integrity->bip_sector & 0xffffffff;
+
+		bip_for_each_vec(iv, bio->bi_integrity, i) {
+			sdt = kmap_atomic(iv->bv_page, KM_USER0)
+				+ iv->bv_offset;
+
+			for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) {
+
+				if (be32_to_cpu(sdt->ref_tag) != virt)
+					goto error;
+
+				sdt->ref_tag = cpu_to_be32(phys);
+				virt++;
+				phys++;
+			}
+
+			kunmap_atomic(sdt, KM_USER0);
+		}
+	}
+
+	return 0;
+
+error:
+	kunmap_atomic(sdt, KM_USER0);
+	sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u\n",
+		  __func__, virt, phys, be32_to_cpu(sdt->ref_tag));
+
+	return -EIO;
+}
+
+/*
+ * Remap physical sector values in the reference tag to the virtual
+ * values expected by the block layer.
+ */
+void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
+{
+	const int tuple_sz = sizeof(struct sd_dif_tuple);
+	struct scsi_disk *sdkp;
+	struct bio *bio;
+	struct sd_dif_tuple *sdt;
+	unsigned int i, j, sectors, sector_sz;
+	u32 phys, virt;
+
+	sdkp = scsi_disk(scmd->request->rq_disk);
+
+	if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0)
+		return;
+
+	sector_sz = scmd->device->sector_size;
+	sectors = good_bytes / sector_sz;
+
+	phys = scmd->request->sector & 0xffffffff;
+	if (sector_sz == 4096)
+		phys >>= 3;
+
+	__rq_for_each_bio(bio, scmd->request) {
+		struct bio_vec *iv;
+
+		virt = bio->bi_integrity->bip_sector & 0xffffffff;
+
+		bip_for_each_vec(iv, bio->bi_integrity, i) {
+			sdt = kmap_atomic(iv->bv_page, KM_USER0)
+				+ iv->bv_offset;
+
+			for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) {
+
+				if (sectors == 0) {
+					kunmap_atomic(sdt, KM_USER0);
+					return;
+				}
+
+				if (be32_to_cpu(sdt->ref_tag) != phys &&
+				    sdt->app_tag != 0xffff)
+					sdt->ref_tag = 0xffffffff; /* Bad ref */
+				else
+					sdt->ref_tag = cpu_to_be32(virt);
+
+				virt++;
+				phys++;
+				sectors--;
+			}
+
+			kunmap_atomic(sdt, KM_USER0);
+		}
+	}
+}
+

+ 4 - 7
drivers/scsi/st.c

@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
  */
 
 
-static const char *verstr = "20080224";
+static const char *verstr = "20080504";
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 
 
@@ -631,7 +631,7 @@ static int cross_eof(struct scsi_tape * STp, int forward)
 /* Flush the write buffer (never need to write if variable blocksize). */
 /* Flush the write buffer (never need to write if variable blocksize). */
 static int st_flush_write_buffer(struct scsi_tape * STp)
 static int st_flush_write_buffer(struct scsi_tape * STp)
 {
 {
-	int offset, transfer, blks;
+	int transfer, blks;
 	int result;
 	int result;
 	unsigned char cmd[MAX_COMMAND_SIZE];
 	unsigned char cmd[MAX_COMMAND_SIZE];
 	struct st_request *SRpnt;
 	struct st_request *SRpnt;
@@ -644,14 +644,10 @@ static int st_flush_write_buffer(struct scsi_tape * STp)
 	result = 0;
 	result = 0;
 	if (STp->dirty == 1) {
 	if (STp->dirty == 1) {
 
 
-		offset = (STp->buffer)->buffer_bytes;
-		transfer = ((offset + STp->block_size - 1) /
-			    STp->block_size) * STp->block_size;
+		transfer = STp->buffer->buffer_bytes;
                 DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n",
                 DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n",
                                tape_name(STp), transfer));
                                tape_name(STp), transfer));
 
 
-		memset((STp->buffer)->b_data + offset, 0, transfer - offset);
-
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = WRITE_6;
 		cmd[0] = WRITE_6;
 		cmd[1] = 1;
 		cmd[1] = 1;
@@ -1670,6 +1666,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
 				if (undone <= do_count) {
 				if (undone <= do_count) {
 					/* Only data from this write is not written */
 					/* Only data from this write is not written */
 					count += undone;
 					count += undone;
+					b_point -= undone;
 					do_count -= undone;
 					do_count -= undone;
 					if (STp->block_size)
 					if (STp->block_size)
 						blks = (transfer - undone) / STp->block_size;
 						blks = (transfer - undone) / STp->block_size;

+ 1 - 1
drivers/scsi/stex.c

@@ -467,7 +467,7 @@ stex_slave_alloc(struct scsi_device *sdev)
 	/* Cheat: usually extracted from Inquiry data */
 	/* Cheat: usually extracted from Inquiry data */
 	sdev->tagged_supported = 1;
 	sdev->tagged_supported = 1;
 
 
-	scsi_activate_tcq(sdev, sdev->host->can_queue);
+	scsi_activate_tcq(sdev, ST_CMD_PER_LUN);
 
 
 	return 0;
 	return 0;
 }
 }

+ 2 - 0
drivers/scsi/sym53c8xx_2/sym_hipd.c

@@ -5741,6 +5741,8 @@ void sym_hcb_free(struct sym_hcb *np)
 
 
 	for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) {
 	for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) {
 		tp = &np->target[target];
 		tp = &np->target[target];
+		if (tp->luntbl)
+			sym_mfree_dma(tp->luntbl, 256, "LUNTBL");
 #if SYM_CONF_MAX_LUN > 1
 #if SYM_CONF_MAX_LUN > 1
 		kfree(tp->lunmp);
 		kfree(tp->lunmp);
 #endif 
 #endif 

+ 4 - 4
drivers/scsi/tmscsim.c

@@ -452,7 +452,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB)
 		/* TODO: error handling */
 		/* TODO: error handling */
 		if (pSRB->SGcount != 1)
 		if (pSRB->SGcount != 1)
 			error = 1;
 			error = 1;
-		DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __FUNCTION__, pcmd->sense_buffer, cmdp->saved_dma_handle));
+		DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __func__, pcmd->sense_buffer, cmdp->saved_dma_handle));
 	/* Map SG list */
 	/* Map SG list */
 	} else if (scsi_sg_count(pcmd)) {
 	} else if (scsi_sg_count(pcmd)) {
 		int nseg;
 		int nseg;
@@ -466,7 +466,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB)
 		if (nseg < 0)
 		if (nseg < 0)
 			error = 1;
 			error = 1;
 		DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\
 		DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\
-			      __FUNCTION__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd)));
+			      __func__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd)));
 	/* Map single segment */
 	/* Map single segment */
 	} else
 	} else
 		pSRB->SGcount = 0;
 		pSRB->SGcount = 0;
@@ -483,11 +483,11 @@ static void dc390_pci_unmap (struct dc390_srb* pSRB)
 
 
 	if (pSRB->SRBFlag) {
 	if (pSRB->SRBFlag) {
 		pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE);
 		pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE);
-		DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle));
+		DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __func__, cmdp->saved_dma_handle));
 	} else {
 	} else {
 		scsi_dma_unmap(pcmd);
 		scsi_dma_unmap(pcmd);
 		DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n",
 		DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n",
-			      __FUNCTION__, scsi_sglist(pcmd), scsi_sg_count(pcmd)));
+			      __func__, scsi_sglist(pcmd), scsi_sg_count(pcmd)));
 	}
 	}
 }
 }
 
 

+ 4 - 4
drivers/scsi/wd7000.c

@@ -148,7 +148,7 @@
  *
  *
  * 2002/10/04 - Alan Cox <alan@redhat.com>
  * 2002/10/04 - Alan Cox <alan@redhat.com>
  *
  *
- * Use dev_id for interrupts, kill __FUNCTION__ pasting
+ * Use dev_id for interrupts, kill __func__ pasting
  * Add a lock for the scb pool, clean up all other cli/sti usage stuff
  * Add a lock for the scb pool, clean up all other cli/sti usage stuff
  * Use the adapter lock for the other places we had the cli's
  * Use the adapter lock for the other places we had the cli's
  *
  *
@@ -640,12 +640,12 @@ static int __init wd7000_setup(char *str)
 	(void) get_options(str, ARRAY_SIZE(ints), ints);
 	(void) get_options(str, ARRAY_SIZE(ints), ints);
 
 
 	if (wd7000_card_num >= NUM_CONFIGS) {
 	if (wd7000_card_num >= NUM_CONFIGS) {
-		printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __FUNCTION__);
+		printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 
 	if ((ints[0] < 3) || (ints[0] > 5)) {
 	if ((ints[0] < 3) || (ints[0] > 5)) {
-		printk(KERN_ERR "%s: Error in command line!  " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __FUNCTION__);
+		printk(KERN_ERR "%s: Error in command line!  " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __func__);
 	} else {
 	} else {
 		for (i = 0; i < NUM_IRQS; i++)
 		for (i = 0; i < NUM_IRQS; i++)
 			if (ints[1] == wd7000_irq[i])
 			if (ints[1] == wd7000_irq[i])
@@ -1642,7 +1642,7 @@ static int wd7000_biosparam(struct scsi_device *sdev,
 			ip[2] = info[2];
 			ip[2] = info[2];
 
 
 			if (info[0] == 255)
 			if (info[0] == 255)
-				printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __FUNCTION__);
+				printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __func__);
 		}
 		}
 	}
 	}
 
 

+ 4 - 4
drivers/scsi/zalon.c

@@ -68,11 +68,11 @@ lasi_scsi_clock(void * hpa, int defaultclock)
 	if (status == PDC_RET_OK) {
 	if (status == PDC_RET_OK) {
 		clock = (int) pdc_result[16];
 		clock = (int) pdc_result[16];
 	} else {
 	} else {
-		printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __FUNCTION__, status);
+		printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __func__, status);
 		clock = defaultclock; 
 		clock = defaultclock; 
 	}
 	}
 
 
-	printk(KERN_DEBUG "%s: SCSI clock %d\n", __FUNCTION__, clock);
+	printk(KERN_DEBUG "%s: SCSI clock %d\n", __func__, clock);
  	return clock;
  	return clock;
 }
 }
 #endif
 #endif
@@ -108,13 +108,13 @@ zalon_probe(struct parisc_device *dev)
 	*/
 	*/
 	dev->irq = gsc_alloc_irq(&gsc_irq);
 	dev->irq = gsc_alloc_irq(&gsc_irq);
 
 
-	printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __FUNCTION__,
+	printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __func__,
 		zalon_vers, dev->irq);
 		zalon_vers, dev->irq);
 
 
 	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM);
 	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM);
 
 
 	if (zalon_vers == 0)
 	if (zalon_vers == 0)
-		printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __FUNCTION__);
+		printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __func__);
 
 
 	memset(&device, 0, sizeof(struct ncr_device));
 	memset(&device, 0, sizeof(struct ncr_device));
 
 

+ 3 - 0
include/scsi/scsi.h

@@ -106,6 +106,7 @@
 #define VARIABLE_LENGTH_CMD   0x7f
 #define VARIABLE_LENGTH_CMD   0x7f
 #define REPORT_LUNS           0xa0
 #define REPORT_LUNS           0xa0
 #define MAINTENANCE_IN        0xa3
 #define MAINTENANCE_IN        0xa3
+#define MAINTENANCE_OUT       0xa4
 #define MOVE_MEDIUM           0xa5
 #define MOVE_MEDIUM           0xa5
 #define EXCHANGE_MEDIUM       0xa6
 #define EXCHANGE_MEDIUM       0xa6
 #define READ_12               0xa8
 #define READ_12               0xa8
@@ -125,6 +126,8 @@
 #define	SAI_READ_CAPACITY_16  0x10
 #define	SAI_READ_CAPACITY_16  0x10
 /* values for maintenance in */
 /* values for maintenance in */
 #define MI_REPORT_TARGET_PGS  0x0a
 #define MI_REPORT_TARGET_PGS  0x0a
+/* values for maintenance out */
+#define MO_SET_TARGET_PGS     0x0a
 
 
 /* Values for T10/04-262r7 */
 /* Values for T10/04-262r7 */
 #define	ATA_16		      0x85	/* 16-byte pass-thru */
 #define	ATA_16		      0x85	/* 16-byte pass-thru */

+ 86 - 0
include/scsi/scsi_cmnd.h

@@ -77,6 +77,9 @@ struct scsi_cmnd {
 	int allowed;
 	int allowed;
 	int timeout_per_command;
 	int timeout_per_command;
 
 
+	unsigned char prot_op;
+	unsigned char prot_type;
+
 	unsigned short cmd_len;
 	unsigned short cmd_len;
 	enum dma_data_direction sc_data_direction;
 	enum dma_data_direction sc_data_direction;
 
 
@@ -87,6 +90,8 @@ struct scsi_cmnd {
 
 
 	/* These elements define the operation we ultimately want to perform */
 	/* These elements define the operation we ultimately want to perform */
 	struct scsi_data_buffer sdb;
 	struct scsi_data_buffer sdb;
+	struct scsi_data_buffer *prot_sdb;
+
 	unsigned underflow;	/* Return error if less than
 	unsigned underflow;	/* Return error if less than
 				   this amount is transferred */
 				   this amount is transferred */
 
 
@@ -208,4 +213,85 @@ static inline int scsi_sg_copy_to_buffer(struct scsi_cmnd *cmd,
 				 buf, buflen);
 				 buf, buflen);
 }
 }
 
 
+/*
+ * The operations below are hints that tell the controller driver how
+ * to handle I/Os with DIF or similar types of protection information.
+ */
+enum scsi_prot_operations {
+	/* Normal I/O */
+	SCSI_PROT_NORMAL = 0,
+
+	/* OS-HBA: Protected, HBA-Target: Unprotected */
+	SCSI_PROT_READ_INSERT,
+	SCSI_PROT_WRITE_STRIP,
+
+	/* OS-HBA: Unprotected, HBA-Target: Protected */
+	SCSI_PROT_READ_STRIP,
+	SCSI_PROT_WRITE_INSERT,
+
+	/* OS-HBA: Protected, HBA-Target: Protected */
+	SCSI_PROT_READ_PASS,
+	SCSI_PROT_WRITE_PASS,
+
+	/* OS-HBA: Protected, HBA-Target: Protected, checksum conversion */
+	SCSI_PROT_READ_CONVERT,
+	SCSI_PROT_WRITE_CONVERT,
+};
+
+static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op)
+{
+	scmd->prot_op = op;
+}
+
+static inline unsigned char scsi_get_prot_op(struct scsi_cmnd *scmd)
+{
+	return scmd->prot_op;
+}
+
+/*
+ * The controller usually does not know anything about the target it
+ * is communicating with.  However, when DIX is enabled the controller
+ * must be know target type so it can verify the protection
+ * information passed along with the I/O.
+ */
+enum scsi_prot_target_type {
+	SCSI_PROT_DIF_TYPE0 = 0,
+	SCSI_PROT_DIF_TYPE1,
+	SCSI_PROT_DIF_TYPE2,
+	SCSI_PROT_DIF_TYPE3,
+};
+
+static inline void scsi_set_prot_type(struct scsi_cmnd *scmd, unsigned char type)
+{
+	scmd->prot_type = type;
+}
+
+static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd)
+{
+	return scmd->prot_type;
+}
+
+static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd)
+{
+	return scmd->request->sector;
+}
+
+static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd)
+{
+	return cmd->prot_sdb ? cmd->prot_sdb->table.nents : 0;
+}
+
+static inline struct scatterlist *scsi_prot_sglist(struct scsi_cmnd *cmd)
+{
+	return cmd->prot_sdb ? cmd->prot_sdb->table.sgl : NULL;
+}
+
+static inline struct scsi_data_buffer *scsi_prot(struct scsi_cmnd *cmd)
+{
+	return cmd->prot_sdb;
+}
+
+#define scsi_for_each_prot_sg(cmd, sg, nseg, __i)		\
+	for_each_sg(scsi_prot_sglist(cmd), sg, nseg, __i)
+
 #endif /* _SCSI_SCSI_CMND_H */
 #endif /* _SCSI_SCSI_CMND_H */

+ 15 - 2
include/scsi/scsi_device.h

@@ -140,7 +140,8 @@ struct scsi_device {
 	unsigned fix_capacity:1;	/* READ_CAPACITY is too high by 1 */
 	unsigned fix_capacity:1;	/* READ_CAPACITY is too high by 1 */
 	unsigned guess_capacity:1;	/* READ_CAPACITY might be too high by 1 */
 	unsigned guess_capacity:1;	/* READ_CAPACITY might be too high by 1 */
 	unsigned retry_hwerror:1;	/* Retry HARDWARE_ERROR */
 	unsigned retry_hwerror:1;	/* Retry HARDWARE_ERROR */
-	unsigned last_sector_bug:1;	/* Always read last sector in a 1 sector read */
+	unsigned last_sector_bug:1;	/* do not use multisector accesses on
+					   SD_LAST_BUGGY_SECTORS */
 
 
 	DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
 	DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
 	struct list_head event_list;	/* asserted events */
 	struct list_head event_list;	/* asserted events */
@@ -167,15 +168,22 @@ struct scsi_device {
 	unsigned long		sdev_data[0];
 	unsigned long		sdev_data[0];
 } __attribute__((aligned(sizeof(unsigned long))));
 } __attribute__((aligned(sizeof(unsigned long))));
 
 
+struct scsi_dh_devlist {
+	char *vendor;
+	char *model;
+};
+
 struct scsi_device_handler {
 struct scsi_device_handler {
 	/* Used by the infrastructure */
 	/* Used by the infrastructure */
 	struct list_head list; /* list of scsi_device_handlers */
 	struct list_head list; /* list of scsi_device_handlers */
-	struct notifier_block nb;
 
 
 	/* Filled by the hardware handler */
 	/* Filled by the hardware handler */
 	struct module *module;
 	struct module *module;
 	const char *name;
 	const char *name;
+	const struct scsi_dh_devlist *devlist;
 	int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
 	int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
+	int (*attach)(struct scsi_device *);
+	void (*detach)(struct scsi_device *);
 	int (*activate)(struct scsi_device *);
 	int (*activate)(struct scsi_device *);
 	int (*prep_fn)(struct scsi_device *, struct request *);
 	int (*prep_fn)(struct scsi_device *, struct request *);
 };
 };
@@ -416,6 +424,11 @@ static inline int scsi_device_enclosure(struct scsi_device *sdev)
 	return sdev->inquiry[6] & (1<<6);
 	return sdev->inquiry[6] & (1<<6);
 }
 }
 
 
+static inline int scsi_device_protection(struct scsi_device *sdev)
+{
+	return sdev->inquiry[5] & (1<<0);
+}
+
 #define MODULE_ALIAS_SCSI_DEVICE(type) \
 #define MODULE_ALIAS_SCSI_DEVICE(type) \
 	MODULE_ALIAS("scsi:t-" __stringify(type) "*")
 	MODULE_ALIAS("scsi:t-" __stringify(type) "*")
 #define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"
 #define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"

+ 11 - 0
include/scsi/scsi_dh.h

@@ -32,6 +32,7 @@ enum {
 	 */
 	 */
 	SCSI_DH_DEV_FAILED,	/* generic device error */
 	SCSI_DH_DEV_FAILED,	/* generic device error */
 	SCSI_DH_DEV_TEMP_BUSY,
 	SCSI_DH_DEV_TEMP_BUSY,
+	SCSI_DH_DEV_UNSUPP,	/* device handler not supported */
 	SCSI_DH_DEVICE_MAX,	/* max device blkerr definition */
 	SCSI_DH_DEVICE_MAX,	/* max device blkerr definition */
 
 
 	/*
 	/*
@@ -57,6 +58,8 @@ enum {
 #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
 #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
 extern int scsi_dh_activate(struct request_queue *);
 extern int scsi_dh_activate(struct request_queue *);
 extern int scsi_dh_handler_exist(const char *);
 extern int scsi_dh_handler_exist(const char *);
+extern int scsi_dh_attach(struct request_queue *, const char *);
+extern void scsi_dh_detach(struct request_queue *);
 #else
 #else
 static inline int scsi_dh_activate(struct request_queue *req)
 static inline int scsi_dh_activate(struct request_queue *req)
 {
 {
@@ -66,4 +69,12 @@ static inline int scsi_dh_handler_exist(const char *name)
 {
 {
 	return 0;
 	return 0;
 }
 }
+static inline int scsi_dh_attach(struct request_queue *req, const char *name)
+{
+	return SCSI_DH_NOSYS;
+}
+static inline void scsi_dh_detach(struct request_queue *q)
+{
+	return;
+}
 #endif
 #endif

+ 2 - 0
include/scsi/scsi_eh.h

@@ -74,7 +74,9 @@ struct scsi_eh_save {
 	/* saved state */
 	/* saved state */
 	int result;
 	int result;
 	enum dma_data_direction data_direction;
 	enum dma_data_direction data_direction;
+	unsigned underflow;
 	unsigned char cmd_len;
 	unsigned char cmd_len;
+	unsigned char prot_op;
 	unsigned char *cmnd;
 	unsigned char *cmnd;
 	struct scsi_data_buffer sdb;
 	struct scsi_data_buffer sdb;
 	struct request *next_rq;
 	struct request *next_rq;

+ 85 - 1
include/scsi/scsi_host.h

@@ -547,7 +547,7 @@ struct Scsi_Host {
 	unsigned int host_failed;	   /* commands that failed. */
 	unsigned int host_failed;	   /* commands that failed. */
 	unsigned int host_eh_scheduled;    /* EH scheduled without command */
 	unsigned int host_eh_scheduled;    /* EH scheduled without command */
     
     
-	unsigned short host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
+	unsigned int host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
 	int resetting; /* if set, it means that last_reset is a valid value */
 	int resetting; /* if set, it means that last_reset is a valid value */
 	unsigned long last_reset;
 	unsigned long last_reset;
 
 
@@ -636,6 +636,10 @@ struct Scsi_Host {
 	 */
 	 */
 	unsigned int max_host_blocked;
 	unsigned int max_host_blocked;
 
 
+	/* Protection Information */
+	unsigned int prot_capabilities;
+	unsigned char prot_guard_type;
+
 	/*
 	/*
 	 * q used for scsi_tgt msgs, async events or any other requests that
 	 * q used for scsi_tgt msgs, async events or any other requests that
 	 * need to be processed in userspace
 	 * need to be processed in userspace
@@ -756,6 +760,86 @@ extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
 extern void scsi_free_host_dev(struct scsi_device *);
 extern void scsi_free_host_dev(struct scsi_device *);
 extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
 extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
 
 
+/*
+ * DIF defines the exchange of protection information between
+ * initiator and SBC block device.
+ *
+ * DIX defines the exchange of protection information between OS and
+ * initiator.
+ */
+enum scsi_host_prot_capabilities {
+	SHOST_DIF_TYPE1_PROTECTION = 1 << 0, /* T10 DIF Type 1 */
+	SHOST_DIF_TYPE2_PROTECTION = 1 << 1, /* T10 DIF Type 2 */
+	SHOST_DIF_TYPE3_PROTECTION = 1 << 2, /* T10 DIF Type 3 */
+
+	SHOST_DIX_TYPE0_PROTECTION = 1 << 3, /* DIX between OS and HBA only */
+	SHOST_DIX_TYPE1_PROTECTION = 1 << 4, /* DIX with DIF Type 1 */
+	SHOST_DIX_TYPE2_PROTECTION = 1 << 5, /* DIX with DIF Type 2 */
+	SHOST_DIX_TYPE3_PROTECTION = 1 << 6, /* DIX with DIF Type 3 */
+};
+
+/*
+ * SCSI hosts which support the Data Integrity Extensions must
+ * indicate their capabilities by setting the prot_capabilities using
+ * this call.
+ */
+static inline void scsi_host_set_prot(struct Scsi_Host *shost, unsigned int mask)
+{
+	shost->prot_capabilities = mask;
+}
+
+static inline unsigned int scsi_host_get_prot(struct Scsi_Host *shost)
+{
+	return shost->prot_capabilities;
+}
+
+static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type)
+{
+	switch (target_type) {
+	case 1: return shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION;
+	case 2: return shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION;
+	case 3: return shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION;
+	}
+
+	return 0;
+}
+
+static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsigned int target_type)
+{
+	switch (target_type) {
+	case 0: return shost->prot_capabilities & SHOST_DIX_TYPE0_PROTECTION;
+	case 1: return shost->prot_capabilities & SHOST_DIX_TYPE1_PROTECTION;
+	case 2: return shost->prot_capabilities & SHOST_DIX_TYPE2_PROTECTION;
+	case 3: return shost->prot_capabilities & SHOST_DIX_TYPE3_PROTECTION;
+	}
+
+	return 0;
+}
+
+/*
+ * All DIX-capable initiators must support the T10-mandated CRC
+ * checksum.  Controllers can optionally implement the IP checksum
+ * scheme which has much lower impact on system performance.  Note
+ * that the main rationale for the checksum is to match integrity
+ * metadata with data.  Detecting bit errors are a job for ECC memory
+ * and buses.
+ */
+
+enum scsi_host_guard_type {
+	SHOST_DIX_GUARD_CRC = 1 << 0,
+	SHOST_DIX_GUARD_IP  = 1 << 1,
+};
+
+static inline void scsi_host_set_guard(struct Scsi_Host *shost, unsigned char type)
+{
+	shost->prot_guard_type = type;
+}
+
+static inline unsigned char scsi_host_get_guard(struct Scsi_Host *shost)
+{
+	return shost->prot_guard_type;
+}
+
 /* legacy interfaces */
 /* legacy interfaces */
 extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
 extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
 extern void scsi_unregister(struct Scsi_Host *);
 extern void scsi_unregister(struct Scsi_Host *);