This code is more posted as an illustration of how to do things than an actual patch for submission. However, I've tested this and it does actually work: ioc1: 53C1030: Capabilities={Initiator,Target} scsi5 : ioc1: LSI53C1030, FwRev=01032700h, Ports=1, MaxQ=255, IRQ=56 Vendor: HP 36.4G Model: ST336607LW Rev: HPC3 Type: Direct-Access ANSI SCSI revision: 03 target5:0:1: Beginning Domain Validation target5:0:1: Ending Domain Validation target5:0:1: FAST-160 WIDE SCSI 320.0 MB/s DT IU QAS (6.25 ns, offset 127) jejb@titanic> ls /sys/class/spi_transport/target5\:0\:1/ device@ iu max_width offset period rd_strm rti wr_flow dt max_offset min_period pcomp_en qas revalidate width James --- a/drivers/message/fusion/Kconfig +++ b/drivers/message/fusion/Kconfig @@ -9,6 +9,7 @@ config FUSION_SPI tristate "Fusion MPT ScsiHost drivers for SPI" depends on PCI && SCSI select FUSION + select SCSI_SPI_ATTRS ---help--- SCSI HOST support for a parallel SCSI host adapters. --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2507,7 +2507,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int /* 4. Renegotiate to all devices, if SCSI */ if (ioc->bus_type == SCSI) { - dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n")); + printk("writeSDP1: ALL_IDS USE_NVRAM\n"); mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM); } @@ -2766,7 +2766,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, i vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; } } - mptscsih_setTargetNegoParms(hd, vdev, data_56); + //mptscsih_setTargetNegoParms(hd, vdev, data_56); } else { /* Initial Inquiry may not request enough data bytes to * obtain byte 57. DV will; if target doesn't return @@ -2777,7 +2777,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, i */ data_56 = data[56]; vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; - mptscsih_setTargetNegoParms(hd, vdev, data_56); + //mptscsih_setTargetNegoParms(hd, vdev, data_56); } } } @@ -2806,6 +2806,8 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOS target->negoFlags = pspi_data->noQas; + printk("HERE\n"); + /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine * support. If available, default QAS to off and allow enabling. * If not available, default QAS to on, turn off for non-disks. @@ -3105,6 +3107,8 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, in u8 negoFlags; u8 maxwidth, maxoffset, maxfactor; + printk("HERE2\n"); + if (ioc->spi_data.sdp1length == 0) return 0; @@ -3204,8 +3208,8 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, in return -EAGAIN; } - ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n", - hd->ioc->name, mf, id, requested, configuration)); + printk(MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n", + hd->ioc->name, mf, id, requested, configuration); /* Set the request and the data pointers. @@ -4228,12 +4232,12 @@ mptscsih_qas_check(MPT_SCSI_HOST *hd, in if ((pTarget != NULL) && (!pTarget->raidVolume)) { if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) { pTarget->negoFlags |= hd->ioc->spi_data.noQas; - dnegoprintk(("writeSDP1: id=%d flags=0\n", id)); + printk("writeSDP1: id=%d flags=0\n", id); mptscsih_writeSDP1(hd, 0, ii, 0); } } else { if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) { - dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id)); + printk("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id); mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM); } } --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -67,7 +67,7 @@ * capabilities. */ -#define MPTSCSIH_ENABLE_DOMAIN_VALIDATION +#undef MPTSCSIH_ENABLE_DOMAIN_VALIDATION /* SCSI driver setup structure. Settings can be overridden --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -62,6 +62,8 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> +#include <scsi/scsi_transport.h> +#include <scsi/scsi_transport_spi.h> #include "mptbase.h" #include "mptscsih.h" @@ -98,6 +100,8 @@ static int mpt_pq_filter = 0; module_param(mpt_pq_filter, int, 0); MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)"); +static struct scsi_transport_template *mptspi_transport_template = NULL; + static int mptspiDoneCtx = -1; static int mptspiTaskCtx = -1; static int mptspiInternalCtx = -1; /* Used only for internal commands */ @@ -115,6 +119,48 @@ static struct device_attribute *mptspi_d NULL, }; +static int mptspi_target_alloc(struct scsi_target *starget) +{ + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + static void mptspi_write_offset(struct scsi_target *, int); + static void mptspi_write_width(struct scsi_target *, int); + + if (hd == NULL) + return -ENODEV; + + if (hd->ioc->spi_data.nvram && + hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { + u32 nvram = hd->ioc->spi_data.nvram[starget->id]; + spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; + spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + } else { + spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor; + spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth; + } + spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset; + + spi_offset(starget) = 0; + mptspi_write_width(starget, 0); + + return 0; +} + +static int mptspi_slave_configure(struct scsi_device *sdev) +{ + int ret = mptscsih_slave_configure(sdev); + + if (ret) + return ret; + + if (!spi_initial_dv(sdev->sdev_target)) { + spi_dv_device(sdev); + spi_display_xfer_agreement(sdev->sdev_target); + } + + return 0; +} + static struct scsi_host_template mptspi_driver_template = { .proc_name = "mptspi", .proc_info = mptscsih_proc_info, @@ -122,8 +168,9 @@ static struct scsi_host_template mptspi_ .info = mptscsih_info, .queuecommand = mptscsih_qcmd, .slave_alloc = mptscsih_slave_alloc, - .slave_configure = mptscsih_slave_configure, + .slave_configure = mptspi_slave_configure, .slave_destroy = mptscsih_slave_destroy, + .target_alloc = mptspi_target_alloc, .eh_abort_handler = mptscsih_abort, .eh_device_reset_handler = mptscsih_dev_reset, .eh_bus_reset_handler = mptscsih_bus_reset, @@ -138,6 +185,325 @@ static struct scsi_host_template mptspi_ .sdev_attrs = mptspi_dev_attrs, }; +static int mptspi_read_page0(struct scsi_target *starget, + struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) +{ + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_ADAPTER *ioc = hd->ioc; + struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0; + dma_addr_t pg0_dma; + int size; + struct _x_config_parms cfg; + struct _CONFIG_PAGE_HEADER hdr; + int err = -EBUSY; + + size = ioc->spi_data.sdp0length * 4; + /* + if (ioc->spi_data.sdp0length & 1) + size += size + 4; + size += 2048; + */ + + pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL); + if (pg0 == NULL) { + dev_printk(KERN_ERR, &starget->dev, "dma_alloc_coherent for parameters failed\n"); + return -EINVAL; + } + + memset(&hdr, 0, sizeof(hdr)); + + hdr.PageVersion = ioc->spi_data.sdp0version; + hdr.PageLength = ioc->spi_data.sdp0length; + hdr.PageNumber = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + + memset(&cfg, 0, sizeof(cfg)); + + cfg.hdr = &hdr; + cfg.physAddr = pg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.dir = 0; + cfg.pageAddr = (starget->channel << 8) | starget->id; + + if (mpt_config(ioc, &cfg)) { + dev_printk(KERN_ERR, &starget->dev, "mpt_config failed\n"); + goto out_free; + } + err = 0; + memcpy(pass_pg0, pg0, size); + + out_free: + dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma); + return err; +} + +static void mptspi_read_parameters(struct scsi_target *starget) +{ + int nego; + struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0; + + mptspi_read_page0(starget, &pg0); + + nego = le32_to_cpu(pg0.NegotiatedParameters); + + spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0; + spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0; + spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0; + //spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0; + spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0; + spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0; + spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0; + spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0; + spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD; + spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET; + spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; +} + +static int mptspi_write_page1(struct scsi_target *starget, + struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1) +{ + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; + struct _MPT_ADAPTER *ioc = hd->ioc; + struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1; + dma_addr_t pg1_dma; + int size; + struct _x_config_parms cfg; + struct _CONFIG_PAGE_HEADER hdr; + int err = -EBUSY; + + size = ioc->spi_data.sdp1length * 4; + + pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); + if (pg1 == NULL) { + dev_printk(KERN_ERR, &starget->dev, "dma_alloc_coherent for parameters failed\n"); + return -EINVAL; + } + + memset(&hdr, 0, sizeof(hdr)); + + hdr.PageVersion = ioc->spi_data.sdp1version; + hdr.PageLength = ioc->spi_data.sdp1length; + hdr.PageNumber = 1; + hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + + memset(&cfg, 0, sizeof(cfg)); + + cfg.hdr = &hdr; + cfg.physAddr = pg1_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + cfg.dir = 1; + cfg.pageAddr = (starget->channel << 8) | starget->id; + + memcpy(pg1, pass_pg1, size); + + pg1->Header.PageVersion = hdr.PageVersion; + pg1->Header.PageLength = hdr.PageLength; + pg1->Header.PageNumber = hdr.PageNumber; + pg1->Header.PageType = hdr.PageType; + + if (mpt_config(ioc, &cfg)) { + dev_printk(KERN_ERR, &starget->dev, "mpt_config failed\n"); + goto out_free; + } + err = 0; + + out_free: + dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma); + return err; +} + +static u32 mptspi_getRP(struct scsi_target *starget) +{ + u32 nego = 0; + + nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0; + nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0; + nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0; + //nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0; + nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0; + nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0; + nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0; + nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0; + + nego |= (spi_period(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; + nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; + nego |= spi_width(starget) ? MPI_SCSIDEVPAGE1_RP_WIDE : 0; + + return nego; +} + +static void mptspi_write_offset(struct scsi_target *starget, int offset) +{ + struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; + u32 nego; + + if (offset < 0) + offset = 0; + + if (offset > 255) + offset = 255; + + if (spi_offset(starget) == -1) + mptspi_read_parameters(starget); + + spi_offset(starget) = offset; + + nego = mptspi_getRP(starget); + + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; + + mptspi_write_page1(starget, &pg1); +} + +static void mptspi_write_period(struct scsi_target *starget, int period) +{ + struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; + u32 nego; + + if (period < 8) + period = 8; + + if (period > 255) + period = 255; + + if (spi_period(starget) == -1) + mptspi_read_parameters(starget); + + if (period == 8) { + spi_iu(starget) = 1; + spi_dt(starget) = 1; + } else if (period == 9) { + spi_dt(starget) = 1; + } + + spi_period(starget) = period; + + nego = mptspi_getRP(starget); + + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; + + mptspi_write_page1(starget, &pg1); +} + +static void mptspi_write_dt(struct scsi_target *starget, int dt) +{ + struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; + u32 nego; + + if (spi_period(starget) == -1) + mptspi_read_parameters(starget); + + if (!dt && spi_period(starget) < 10) + spi_period(starget) = 10; + + spi_dt(starget) = dt; + + nego = mptspi_getRP(starget); + + + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; + + mptspi_write_page1(starget, &pg1); +} + +static void mptspi_write_iu(struct scsi_target *starget, int iu) +{ + struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; + u32 nego; + + if (spi_period(starget) == -1) + mptspi_read_parameters(starget); + + if (!iu && spi_period(starget) < 9) + spi_period(starget) = 9; + + spi_iu(starget) = iu; + + nego = mptspi_getRP(starget); + + + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; + + mptspi_write_page1(starget, &pg1); +} + +static void mptspi_write_qas(struct scsi_target *starget, int qas) +{ + struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; + u32 nego; + + spi_qas(starget) = qas; + + nego = mptspi_getRP(starget); + + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; + + mptspi_write_page1(starget, &pg1); +} + +static void mptspi_write_width(struct scsi_target *starget, int width) +{ + struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; + u32 nego; + + if (!width) { + spi_dt(starget) = 0; + if (spi_period(starget) < 10) + spi_period(starget) = 10; + } + + spi_width(starget) = width; + + nego = mptspi_getRP(starget); + + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; + + mptspi_write_page1(starget, &pg1); +} + +static struct spi_function_template mptspi_transport_functions = { + .get_offset = mptspi_read_parameters, + .set_offset = mptspi_write_offset, + .show_offset = 1, + .get_period = mptspi_read_parameters, + .set_period = mptspi_write_period, + .show_period = 1, + .get_width = mptspi_read_parameters, + .set_width = mptspi_write_width, + .show_width = 1, + .get_iu = mptspi_read_parameters, + .set_iu = mptspi_write_iu, + .show_iu = 1, + .get_dt = mptspi_read_parameters, + .set_dt = mptspi_write_dt, + .show_dt = 1, + .get_qas = mptspi_read_parameters, + .set_qas = mptspi_write_qas, + .show_qas = 1, + .get_wr_flow = mptspi_read_parameters, + .show_wr_flow = 1, + .get_rd_strm = mptspi_read_parameters, + .show_rd_strm = 1, + .get_rti = mptspi_read_parameters, + .show_rti = 1, + .get_pcomp_en = mptspi_read_parameters, + .show_pcomp_en = 1, +}; + /**************************************************************************** * Supported hardware @@ -382,7 +748,6 @@ mptspi_probe(struct pci_dev *pdev, const mpt_saf_te, mpt_pq_filter)); #endif - ioc->spi_data.forceDv = 0; ioc->spi_data.noQas = 0; @@ -398,6 +763,11 @@ mptspi_probe(struct pci_dev *pdev, const hd->scandv_wait_done = 0; hd->last_queue_full = 0; + /* Some versions of the firmware don't support page 0; without + * that we can't get the parameters */ + if (hd->ioc->spi_data.sdp0length != 0) + sh->transportt = mptspi_transport_template; + error = scsi_add_host (sh, &ioc->pcidev->dev); if(error) { dprintk((KERN_ERR MYNAM @@ -441,6 +811,10 @@ mptspi_init(void) show_mptmod_ver(my_NAME, my_VERSION); + mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions); + if (!mptspi_transport_template) + return -ENODEV; + mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER); mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER); mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER); - : send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html