📄 sbp2.c
字号:
sense_data[4] = sbp2_status[13]; sense_data[5] = sbp2_status[14]; sense_data[6] = sbp2_status[15]; sense_data[7] = 10; sense_data[8] = sbp2_status[16]; sense_data[9] = sbp2_status[17]; sense_data[10] = sbp2_status[18]; sense_data[11] = sbp2_status[19]; sense_data[12] = sbp2_status[10]; sense_data[13] = sbp2_status[11]; sense_data[14] = sbp2_status[20]; sense_data[15] = sbp2_status[21]; return sbp2_status[8] & 0x3f;}static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data, u64 addr, size_t length, u16 fl){ struct sbp2_fwhost_info *hi; struct sbp2_lu *lu = NULL, *lu_tmp; struct scsi_cmnd *SCpnt = NULL; struct sbp2_status_block *sb; u32 scsi_status = SBP2_SCSI_STATUS_GOOD; struct sbp2_command_info *cmd; unsigned long flags; if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) { SBP2_ERR("Wrong size of status block"); return RCODE_ADDRESS_ERROR; } if (unlikely(!host)) { SBP2_ERR("host is NULL - this is bad!"); return RCODE_ADDRESS_ERROR; } hi = hpsb_get_hostinfo(&sbp2_highlevel, host); if (unlikely(!hi)) { SBP2_ERR("host info is NULL - this is bad!"); return RCODE_ADDRESS_ERROR; } /* Find the unit which wrote the status. */ list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) { if (lu_tmp->ne->nodeid == nodeid && lu_tmp->status_fifo_addr == addr) { lu = lu_tmp; break; } } if (unlikely(!lu)) { SBP2_ERR("lu is NULL - device is gone?"); return RCODE_ADDRESS_ERROR; } /* Put response into lu status fifo buffer. The first two bytes * come in big endian bit order. Often the target writes only a * truncated status block, minimally the first two quadlets. The rest * is implied to be zeros. */ sb = &lu->status_block; memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent)); memcpy(sb, data, length); sbp2util_be32_to_cpu_buffer(sb, 8); /* Ignore unsolicited status. Handle command ORB status. */ if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2)) cmd = NULL; else cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo); if (cmd) { dma_sync_single_for_cpu(hi->host->device.parent, cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); /* Grab SCSI command pointers and check status. */ /* * FIXME: If the src field in the status is 1, the ORB DMA must * not be reused until status for a subsequent ORB is received. */ SCpnt = cmd->Current_SCpnt; spin_lock_irqsave(&lu->cmd_orb_lock, flags); sbp2util_mark_command_completed(lu, cmd); spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); if (SCpnt) { u32 h = sb->ORB_offset_hi_misc; u32 r = STATUS_GET_RESP(h); if (r != RESP_STATUS_REQUEST_COMPLETE) { SBP2_INFO("resp 0x%x, sbp_status 0x%x", r, STATUS_GET_SBP_STATUS(h)); scsi_status = r == RESP_STATUS_TRANSPORT_FAILURE ? SBP2_SCSI_STATUS_BUSY : SBP2_SCSI_STATUS_COMMAND_TERMINATED; } if (STATUS_GET_LEN(h) > 1) scsi_status = sbp2_status_to_sense_data( (unchar *)sb, SCpnt->sense_buffer); if (STATUS_TEST_DEAD(h)) sbp2_agent_reset(lu, 0); } /* Check here to see if there are no commands in-use. If there * are none, we know that the fetch agent left the active state * _and_ that we did not reactivate it yet. Therefore clear * last_orb so that next time we write directly to the * ORB_POINTER register. That way the fetch agent does not need * to refetch the next_ORB. */ spin_lock_irqsave(&lu->cmd_orb_lock, flags); if (list_empty(&lu->cmd_orb_inuse)) lu->last_orb = NULL; spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); } else { /* It's probably status after a management request. */ if ((sb->ORB_offset_lo == lu->reconnect_orb_dma) || (sb->ORB_offset_lo == lu->login_orb_dma) || (sb->ORB_offset_lo == lu->query_logins_orb_dma) || (sb->ORB_offset_lo == lu->logout_orb_dma)) { lu->access_complete = 1; wake_up_interruptible(&sbp2_access_wq); } } if (SCpnt) sbp2scsi_complete_command(lu, scsi_status, SCpnt, cmd->Current_done); return RCODE_COMPLETE;}/************************************** * SCSI interface related section **************************************/static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0]; struct sbp2_fwhost_info *hi; int result = DID_NO_CONNECT << 16; if (unlikely(!sbp2util_node_is_available(lu))) goto done; hi = lu->hi; if (unlikely(!hi)) { SBP2_ERR("sbp2_fwhost_info is NULL - this is bad!"); goto done; } /* Multiple units are currently represented to the SCSI core as separate * targets, not as one target with multiple LUs. Therefore return * selection time-out to any IO directed at non-zero LUNs. */ if (unlikely(SCpnt->device->lun)) goto done; if (unlikely(!hpsb_node_entry_valid(lu->ne))) { SBP2_ERR("Bus reset in progress - rejecting command"); result = DID_BUS_BUSY << 16; goto done; } /* Bidirectional commands are not yet implemented, * and unknown transfer direction not handled. */ if (unlikely(SCpnt->sc_data_direction == DMA_BIDIRECTIONAL)) { SBP2_ERR("Cannot handle DMA_BIDIRECTIONAL - rejecting command"); result = DID_ERROR << 16; goto done; } if (sbp2_send_command(lu, SCpnt, done)) { SBP2_ERR("Error sending SCSI command"); sbp2scsi_complete_command(lu, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, SCpnt, done); } return 0;done: SCpnt->result = result; done(SCpnt); return 0;}static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status){ struct sbp2_fwhost_info *hi = lu->hi; struct list_head *lh; struct sbp2_command_info *cmd; unsigned long flags; spin_lock_irqsave(&lu->cmd_orb_lock, flags); while (!list_empty(&lu->cmd_orb_inuse)) { lh = lu->cmd_orb_inuse.next; cmd = list_entry(lh, struct sbp2_command_info, list); dma_sync_single_for_cpu(hi->host->device.parent, cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(lu, cmd); if (cmd->Current_SCpnt) { cmd->Current_SCpnt->result = status << 16; cmd->Current_done(cmd->Current_SCpnt); } } spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return;}/* * Complete a regular SCSI command. Can be called in atomic context. */static void sbp2scsi_complete_command(struct sbp2_lu *lu, u32 scsi_status, struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ if (!SCpnt) { SBP2_ERR("SCpnt is NULL"); return; } switch (scsi_status) { case SBP2_SCSI_STATUS_GOOD: SCpnt->result = DID_OK << 16; break; case SBP2_SCSI_STATUS_BUSY: SBP2_ERR("SBP2_SCSI_STATUS_BUSY"); SCpnt->result = DID_BUS_BUSY << 16; break; case SBP2_SCSI_STATUS_CHECK_CONDITION: SCpnt->result = CHECK_CONDITION << 1 | DID_OK << 16; break; case SBP2_SCSI_STATUS_SELECTION_TIMEOUT: SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT"); SCpnt->result = DID_NO_CONNECT << 16; scsi_print_command(SCpnt); break; case SBP2_SCSI_STATUS_CONDITION_MET: case SBP2_SCSI_STATUS_RESERVATION_CONFLICT: case SBP2_SCSI_STATUS_COMMAND_TERMINATED: SBP2_ERR("Bad SCSI status = %x", scsi_status); SCpnt->result = DID_ERROR << 16; scsi_print_command(SCpnt); break; default: SBP2_ERR("Unsupported SCSI status = %x", scsi_status); SCpnt->result = DID_ERROR << 16; } /* If a bus reset is in progress and there was an error, complete * the command as busy so that it will get retried. */ if (!hpsb_node_entry_valid(lu->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { SBP2_ERR("Completing command with busy (bus reset)"); SCpnt->result = DID_BUS_BUSY << 16; } /* Tell the SCSI stack that we're done with this command. */ done(SCpnt);}static int sbp2scsi_slave_alloc(struct scsi_device *sdev){ struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0]; lu->sdev = sdev; sdev->allow_restart = 1; if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36) sdev->inquiry_len = 36; return 0;}static int sbp2scsi_slave_configure(struct scsi_device *sdev){ struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0]; sdev->use_10_for_rw = 1; if (sdev->type == TYPE_ROM) sdev->use_10_for_ms = 1; if (sdev->type == TYPE_DISK && lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) sdev->skip_ms_page_8 = 1; if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) sdev->fix_capacity = 1; return 0;}static void sbp2scsi_slave_destroy(struct scsi_device *sdev){ ((struct sbp2_lu *)sdev->host->hostdata[0])->sdev = NULL; return;}/* * Called by scsi stack when something has really gone wrong. * Usually called when a command has timed-out for some reason. */static int sbp2scsi_abort(struct scsi_cmnd *SCpnt){ struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0]; struct sbp2_fwhost_info *hi = lu->hi; struct sbp2_command_info *cmd; unsigned long flags; SBP2_INFO("aborting sbp2 command"); scsi_print_command(SCpnt); if (sbp2util_node_is_available(lu)) { sbp2_agent_reset(lu, 1); /* Return a matching command structure to the free pool. */ spin_lock_irqsave(&lu->cmd_orb_lock, flags); cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt); if (cmd) { dma_sync_single_for_cpu(hi->host->device.parent, cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(lu, cmd); if (cmd->Current_SCpnt) { cmd->Current_SCpnt->result = DID_ABORT << 16; cmd->Current_done(cmd->Current_SCpnt); } } spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY); } return SUCCESS;}/* * Called by scsi stack when something has really gone wrong. */static int sbp2scsi_reset(struct scsi_cmnd *SCpnt){ struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0]; SBP2_INFO("reset requested"); if (sbp2util_node_is_available(lu)) { SBP2_INFO("generating sbp2 fetch agent reset"); sbp2_agent_reset(lu, 1); } return SUCCESS;}static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr, char *buf){ struct scsi_device *sdev; struct sbp2_lu *lu; if (!(sdev = to_scsi_device(dev))) return 0; if (!(lu = (struct sbp2_lu *)sdev->host->hostdata[0])) return 0; return sprintf(buf, "%016Lx:%d:%d\n", (unsigned long long)lu->ne->guid, lu->ud->id, ORB_SET_LUN(lu->lun));}MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);MODULE_LICENSE("GPL");static int sbp2_module_init(void){ int ret; if (sbp2_serialize_io) { sbp2_shost_template.can_queue = 1; sbp2_shost_template.cmd_per_lun = 1; } if (sbp2_default_workarounds & SBP2_WORKAROUND_128K_MAX_TRANS && (sbp2_max_sectors * 512) > (128 * 1024)) sbp2_max_sectors = 128 * 1024 / 512; sbp2_shost_template.max_sectors = sbp2_max_sectors; hpsb_register_highlevel(&sbp2_highlevel); ret = hpsb_register_protocol(&sbp2_driver); if (ret) { SBP2_ERR("Failed to register protocol"); hpsb_unregister_highlevel(&sbp2_highlevel); return ret; } return 0;}static void __exit sbp2_module_exit(void){ hpsb_unregister_protocol(&sbp2_driver); hpsb_unregister_highlevel(&sbp2_highlevel);}module_init(sbp2_module_init);module_exit(sbp2_module_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -