📄 mptspi.c
字号:
size = ioc->spi_data.sdp0length * 4; /* if (ioc->spi_data.sdp0length & 1) size += size + 4; size += 2048; */ spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL); if (spi_dev_pg0 == NULL) { starget_printk(KERN_ERR, starget, MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name); 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.cfghdr.hdr = &hdr; cfg.physAddr = spi_dev_pg0_dma; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; cfg.dir = 0; cfg.pageAddr = starget->id; if (mpt_config(ioc, &cfg)) { starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); goto out_free; } err = 0; memcpy(pass_pg0, spi_dev_pg0, size); mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters)); out_free: dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_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_read_parameters(struct scsi_target *starget){ int nego; struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0; mptspi_read_spi_device_pg0(starget, &spi_dev_pg0); nego = le32_to_cpu(spi_dev_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_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_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 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 intmptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id){ MpiRaidActionRequest_t *pReq; MPT_FRAME_HDR *mf; MPT_ADAPTER *ioc = hd->ioc; /* Get and Populate a free Frame */ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", ioc->name)); return -EAGAIN; } pReq = (MpiRaidActionRequest_t *)mf; if (quiesce) pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO; else pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO; pReq->Reserved1 = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_RAID_ACTION; pReq->VolumeID = id; pReq->VolumeBus = channel; pReq->PhysDiskNum = 0; pReq->MsgFlags = 0; pReq->Reserved2 = 0; pReq->ActionDataWord = 0; /* Reserved for this action */ mpt_add_sge((char *)&pReq->ActionDataSGE, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", ioc->name, pReq->Action, channel, id)); hd->pLocal = NULL; hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ hd->scandv_wait_done = 0; /* Save cmd pointer, for resource free if timeout or * FW reload occurs */ hd->cmdPtr = mf; add_timer(&hd->timer); mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); wait_event(hd->scandv_waitq, hd->scandv_wait_done); if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0)) return -1; return 0;}static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, struct scsi_device *sdev){ VirtTarget *vtarget = scsi_target(sdev)->hostdata; MPT_ADAPTER *ioc = hd->ioc; /* no DV on RAID devices */ if (sdev->channel == 0 && mptspi_is_raid(hd, sdev->id)) return; /* If this is a piece of a RAID, then quiesce first */ if (sdev->channel == 1 && mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT "Integrated RAID quiesce failed\n", ioc->name); return; } hd->spi_pending |= (1 << sdev->id); spi_dv_device(sdev); hd->spi_pending &= ~(1 << sdev->id); if (sdev->channel == 1 && mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT "Integrated RAID resume failed\n", ioc->name); mptspi_read_parameters(sdev->sdev_target); spi_display_xfer_agreement(sdev->sdev_target); mptspi_read_parameters(sdev->sdev_target);}static int mptspi_slave_alloc(struct scsi_device *sdev){ MPT_SCSI_HOST *hd = shost_priv(sdev->host); VirtTarget *vtarget; VirtDevice *vdevice; struct scsi_target *starget; MPT_ADAPTER *ioc = hd->ioc; if (sdev->channel == 1 && mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0) return -ENXIO; vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); if (!vdevice) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", ioc->name, sizeof(VirtDevice)); return -ENOMEM; } vdevice->lun = sdev->lun; sdev->hostdata = vdevice; starget = scsi_target(sdev); vtarget = starget->hostdata; vdevice->vtarget = vtarget; vtarget->num_luns++; if (sdev->channel == 1) sdev->no_uld_attach = 1; return 0;}static int mptspi_slave_configure(struct scsi_device *sdev){ struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host); VirtTarget *vtarget = scsi_target(sdev)->hostdata; int ret; mptspi_initTarget(hd, vtarget, sdev); ret = mptscsih_slave_configure(sdev); if (ret) return ret; ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x" " max_offset=0x%02x max_width=%d\n", hd->ioc->name, sdev->id, spi_min_period(scsi_target(sdev)), spi_max_offset(scsi_target(sdev)), spi_max_width(scsi_target(sdev)))); if ((sdev->channel == 1 || !(mptspi_is_raid(hd, sdev->id))) && !spi_initial_dv(sdev->sdev_target)) mptspi_dv_device(hd, sdev); return 0;}static intmptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host); VirtDevice *vdevice = SCpnt->device->hostdata; MPT_ADAPTER *ioc = hd->ioc; if (!vdevice || !vdevice->vtarget) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } if (SCpnt->device->channel == 1 && mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } if (spi_dv_pending(scsi_target(SCpnt->device))) ddvprintk(ioc, scsi_print_command(SCpnt)); return mptscsih_qcmd(SCpnt,done);}static void mptspi_slave_destroy(struct scsi_device *sdev){ struct scsi_target *starget = scsi_target(sdev); VirtTarget *vtarget = starget->hostdata; VirtDevice *vdevice = sdev->hostdata; /* Will this be the last lun on a non-raid device? */ if (vtarget->num_luns == 1 && vdevice->configured_lun) { struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; /* Async Narrow */ pg1.RequestedParameters = 0; pg1.Reserved = 0; pg1.Configuration = 0; mptspi_write_spi_device_pg1(starget, &pg1); } mptscsih_slave_destroy(sdev);}static struct scsi_host_template mptspi_driver_template = { .module = THIS_MODULE, .proc_name = "mptspi", .proc_info = mptscsih_proc_info, .name = "MPT SPI Host", .info = mptscsih_info, .queuecommand = mptspi_qcmd, .target_alloc = mptspi_target_alloc, .slave_alloc = mptspi_slave_alloc, .slave_configure = mptspi_slave_configure, .target_destroy = mptspi_target_destroy, .slave_destroy = mptspi_slave_destroy, .change_queue_depth = mptscsih_change_queue_depth, .eh_abort_handler = mptscsih_abort, .eh_device_reset_handler = mptscsih_dev_reset, .eh_bus_reset_handler = mptscsih_bus_reset, .eh_host_reset_handler = mptscsih_host_reset, .bios_param = mptscsih_bios_param, .can_queue = MPT_SCSI_CAN_QUEUE, .this_id = -1, .sg_tablesize = MPT_SCSI_SG_DEPTH, .max_sectors = 8192, .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mptscsih_host_attrs,};static int mptspi_write_spi_device_pg1(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 = shost_priv(shost); 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; /* don't allow updating nego parameters on RAID devices */ if (starget->channel == 0 && mptspi_is_raid(hd, starget->id)) return -1; size = ioc->spi_data.sdp1length * 4; pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); if (pg1 == NULL) { starget_printk(KERN_ERR, starget, MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name); 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.cfghdr.hdr = &hdr; cfg.physAddr = pg1_dma; cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; cfg.pageAddr = 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; mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); if (mpt_config(ioc, &cfg)) { starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); goto out_free; } err = 0; out_free: dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma); return err;}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_spi_device_pg1(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_spi_device_pg1(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_spi_device_pg1(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_spi_device_pg1(starget, &pg1);}#define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) \static void mptspi_write_##parm(struct scsi_target *starget, int parm)\{ \ struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; \ u32 nego; \ \ spi_##parm(starget) = parm; \ \ nego = mptspi_getRP(starget); \ \ pg1.RequestedParameters = cpu_to_le32(nego); \ pg1.Reserved = 0; \ pg1.Configuration = 0; \ \ mptspi_write_spi_device_pg1(starget, &pg1); \}MPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm)MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)MPTSPI_SIMPLE_TRANSPORT_PARM(rti)MPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs)MPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en)static void mptspi_write_qas(struct scsi_target *starget, int qas){ struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct _MPT_SCSI_HOST *hd = shost_priv(shost); VirtTarget *vtarget = starget->hostdata; u32 nego; if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) || hd->ioc->spi_data.noQas) spi_qas(starget) = 0; else spi_qas(starget) = qas; nego = mptspi_getRP(starget); pg1.RequestedParameters = cpu_to_le32(nego); pg1.Reserved = 0; pg1.Configuration = 0; mptspi_write_spi_device_pg1(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -