📄 megaraid_mbox.c
字号:
* convert the command issued by mid-layer to format understood by megaraid * firmware. We also complete certain command without sending them to firmware */static scb_t *megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy){ mraid_device_t *rdev = ADAP2RAIDDEV(adapter); int channel; int target; int islogical; mbox_ccb_t *ccb; mraid_passthru_t *pthru; mbox64_t *mbox64; mbox_t *mbox; scb_t *scb; char skip[] = "skipping"; char scan[] = "scanning"; char *ss; /* * Get the appropriate device map for the device this command is * intended for */ MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical); /* * Logical drive commands */ if (islogical) { switch (scp->cmnd[0]) { case TEST_UNIT_READY: /* * Do we support clustering and is the support enabled * If no, return success always */ if (!adapter->ha) { scp->result = (DID_OK << 16); return NULL; } if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); *busy = 1; return NULL; } scb->dma_direction = scp->sc_data_direction; scb->dev_channel = 0xFF; scb->dev_target = target; ccb = (mbox_ccb_t *)scb->ccb; /* * The command id will be provided by the command * issuance routine */ ccb->raw_mbox[0] = CLUSTER_CMD; ccb->raw_mbox[2] = RESERVATION_STATUS; ccb->raw_mbox[3] = target; return scb; case MODE_SENSE: if (scp->use_sg) { struct scatterlist *sgl; caddr_t vaddr; sgl = (struct scatterlist *)scp->request_buffer; if (sgl->page) { vaddr = (caddr_t) (page_address((&sgl[0])->page) + (&sgl[0])->offset); memset(vaddr, 0, scp->cmnd[4]); } else { con_log(CL_ANN, (KERN_WARNING "megaraid mailbox: invalid sg:%d\n", __LINE__)); } } else { memset(scp->request_buffer, 0, scp->cmnd[4]); } scp->result = (DID_OK << 16); return NULL; case INQUIRY: /* * Display the channel scan for logical drives * Do not display scan for a channel if already done. */ if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { con_log(CL_ANN, (KERN_INFO "scsi[%d]: scanning scsi channel %d", adapter->host->host_no, SCP2CHANNEL(scp))); con_log(CL_ANN, ( " [virtual] for logical drives\n")); rdev->last_disp |= (1L << SCP2CHANNEL(scp)); } /* Fall through */ case READ_CAPACITY: /* * Do not allow LUN > 0 for logical drives and * requests for more than 40 logical drives */ if (SCP2LUN(scp)) { scp->result = (DID_BAD_TARGET << 16); return NULL; } if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) { scp->result = (DID_BAD_TARGET << 16); return NULL; } /* Allocate a SCB and initialize passthru */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); *busy = 1; return NULL; } ccb = (mbox_ccb_t *)scb->ccb; scb->dev_channel = 0xFF; scb->dev_target = target; pthru = ccb->pthru; mbox = ccb->mbox; mbox64 = ccb->mbox64; pthru->timeout = 0; pthru->ars = 1; pthru->reqsenselen = 14; pthru->islogical = 1; pthru->logdrv = target; pthru->cdblen = scp->cmd_len; memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); mbox->cmd = MBOXCMD_PASSTHRU64; scb->dma_direction = scp->sc_data_direction; pthru->dataxferlen = scp->request_bufflen; pthru->dataxferaddr = ccb->sgl_dma_h; pthru->numsge = megaraid_mbox_mksgl(adapter, scb); mbox->xferaddr = 0xFFFFFFFF; mbox64->xferaddr_lo = (uint32_t )ccb->pthru_dma_h; mbox64->xferaddr_hi = 0; return scb; case READ_6: case WRITE_6: case READ_10: case WRITE_10: case READ_12: case WRITE_12: /* * Allocate a SCB and initialize mailbox */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); *busy = 1; return NULL; } ccb = (mbox_ccb_t *)scb->ccb; scb->dev_channel = 0xFF; scb->dev_target = target; mbox = ccb->mbox; mbox64 = ccb->mbox64; mbox->logdrv = target; /* * A little HACK: 2nd bit is zero for all scsi read * commands and is set for all scsi write commands */ mbox->cmd = (scp->cmnd[0] & 0x02) ? MBOXCMD_LWRITE64: MBOXCMD_LREAD64 ; /* * 6-byte READ(0x08) or WRITE(0x0A) cdb */ if (scp->cmd_len == 6) { mbox->numsectors = (uint32_t)scp->cmnd[4]; mbox->lba = ((uint32_t)scp->cmnd[1] << 16) | ((uint32_t)scp->cmnd[2] << 8) | (uint32_t)scp->cmnd[3]; mbox->lba &= 0x1FFFFF; } /* * 10-byte READ(0x28) or WRITE(0x2A) cdb */ else if (scp->cmd_len == 10) { mbox->numsectors = (uint32_t)scp->cmnd[8] | ((uint32_t)scp->cmnd[7] << 8); mbox->lba = ((uint32_t)scp->cmnd[2] << 24) | ((uint32_t)scp->cmnd[3] << 16) | ((uint32_t)scp->cmnd[4] << 8) | (uint32_t)scp->cmnd[5]; } /* * 12-byte READ(0xA8) or WRITE(0xAA) cdb */ else if (scp->cmd_len == 12) { mbox->lba = ((uint32_t)scp->cmnd[2] << 24) | ((uint32_t)scp->cmnd[3] << 16) | ((uint32_t)scp->cmnd[4] << 8) | (uint32_t)scp->cmnd[5]; mbox->numsectors = ((uint32_t)scp->cmnd[6] << 24) | ((uint32_t)scp->cmnd[7] << 16) | ((uint32_t)scp->cmnd[8] << 8) | (uint32_t)scp->cmnd[9]; } else { con_log(CL_ANN, (KERN_WARNING "megaraid: unsupported CDB length\n")); megaraid_dealloc_scb(adapter, scb); scp->result = (DID_ERROR << 16); return NULL; } scb->dma_direction = scp->sc_data_direction; // Calculate Scatter-Gather info mbox64->xferaddr_lo = (uint32_t )ccb->sgl_dma_h; mbox->numsge = megaraid_mbox_mksgl(adapter, scb); mbox->xferaddr = 0xFFFFFFFF; mbox64->xferaddr_hi = 0; return scb; case RESERVE: case RELEASE: /* * Do we support clustering and is the support enabled */ if (!adapter->ha) { scp->result = (DID_BAD_TARGET << 16); return NULL; } /* * Allocate a SCB and initialize mailbox */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); *busy = 1; return NULL; } ccb = (mbox_ccb_t *)scb->ccb; scb->dev_channel = 0xFF; scb->dev_target = target; ccb->raw_mbox[0] = CLUSTER_CMD; ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? RESERVE_LD : RELEASE_LD; ccb->raw_mbox[3] = target; scb->dma_direction = scp->sc_data_direction; return scb; default: scp->result = (DID_BAD_TARGET << 16); return NULL; } } else { // Passthru device commands // Do not allow access to target id > 15 or LUN > 7 if (target > 15 || SCP2LUN(scp) > 7) { scp->result = (DID_BAD_TARGET << 16); return NULL; } // if fast load option was set and scan for last device is // over, reset the fast_load flag so that during a possible // next scan, devices can be made available if (rdev->fast_load && (target == 15) && (SCP2CHANNEL(scp) == adapter->max_channel -1)) { con_log(CL_ANN, (KERN_INFO "megaraid[%d]: physical device scan re-enabled\n", adapter->host->host_no)); rdev->fast_load = 0; } /* * Display the channel scan for physical devices */ if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { ss = rdev->fast_load ? skip : scan; con_log(CL_ANN, (KERN_INFO "scsi[%d]: %s scsi channel %d [Phy %d]", adapter->host->host_no, ss, SCP2CHANNEL(scp), channel)); con_log(CL_ANN, ( " for non-raid devices\n")); rdev->last_disp |= (1L << SCP2CHANNEL(scp)); } // disable channel sweep if fast load option given if (rdev->fast_load) { scp->result = (DID_BAD_TARGET << 16); return NULL; } // Allocate a SCB and initialize passthru if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); *busy = 1; return NULL; } ccb = (mbox_ccb_t *)scb->ccb; scb->dev_channel = channel; scb->dev_target = target; scb->dma_direction = scp->sc_data_direction; mbox = ccb->mbox; mbox64 = ccb->mbox64; // Does this firmware support extended CDBs if (adapter->max_cdb_sz == 16) { mbox->cmd = MBOXCMD_EXTPTHRU; megaraid_mbox_prepare_epthru(adapter, scb, scp); mbox64->xferaddr_lo = (uint32_t)ccb->epthru_dma_h; mbox64->xferaddr_hi = 0; mbox->xferaddr = 0xFFFFFFFF; } else { mbox->cmd = MBOXCMD_PASSTHRU64; megaraid_mbox_prepare_pthru(adapter, scb, scp); mbox64->xferaddr_lo = (uint32_t)ccb->pthru_dma_h; mbox64->xferaddr_hi = 0; mbox->xferaddr = 0xFFFFFFFF; } return scb; } // NOT REACHED}/** * megaraid_mbox_runpendq - execute commands queued in the pending queue * @adapter : controller's soft state * @scb : SCB to be queued in the pending list * * scan the pending list for commands which are not yet issued and try to * post to the controller. The SCB can be a null pointer, which would indicate * no SCB to be queue, just try to execute the ones in the pending list. * * NOTE: We do not actually traverse the pending list. The SCBs are plucked * out from the head of the pending list. If it is successfully issued, the * next SCB is at the head now. */static voidmegaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q){ scb_t *scb; unsigned long flags; spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); if (scb_q) { scb_q->state = SCB_PENDQ; list_add_tail(&scb_q->list, &adapter->pend_list); } // if the adapter in not in quiescent mode, post the commands to FW if (adapter->quiescent) { spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); return; } while (!list_empty(&adapter->pend_list)) { assert_spin_locked(PENDING_LIST_LOCK(adapter)); scb = list_entry(adapter->pend_list.next, scb_t, list); // remove the scb from the pending list and try to // issue. If we are unable to issue it, put back in // the pending list and return list_del_init(&scb->list); spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); // if mailbox was busy, return SCB back to pending // list. Make sure to add at the head, since that's // where it would have been removed from scb->state = SCB_ISSUED; if (mbox_post_cmd(adapter, scb) != 0) { spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); scb->state = SCB_PENDQ; list_add(&scb->list, &adapter->pend_list); spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); return; } spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); } spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); return;}/** * megaraid_mbox_prepare_pthru - prepare a command for physical devices * @adapter - pointer to controller's soft state * @scb - scsi control block * @scp - scsi command from the mid-layer * * prepare a command for the scsi physical devices */static voidmegaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb, struct scsi_cmnd *scp){ mbox_ccb_t *ccb; mraid_passthru_t *pthru; uint8_t channel; uint8_t target; ccb = (mbox_ccb_t *)scb->ccb; pthru = ccb->pthru; channel = scb->dev_channel; target = scb->dev_target; // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout pthru->timeout = 4; pthru->ars = 1; pthru->islogical = 0; pthru->channel = 0; pthru->target = (channel << 4) | target; pthru->logdrv = SCP2LUN(scp); pthru->reqsenselen = 14; pthru->cdblen = scp->cmd_len; memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); if (scp->request_bufflen) { pthru->dataxferlen = scp->request_bufflen; pthru->dataxferaddr = ccb->sgl_dma_h; pthru->numsge = megaraid_mbox_mksgl(adapter, scb); } else { pthru->dataxferaddr = 0; pthru->dataxferlen = 0; pthru->numsge = 0; } return;}/** * megaraid_mbox_prepare_epthru - prepare a command for physical devices * @adapter - pointer to controller's soft state * @scb - scsi control block * @scp - scsi command from the mid-layer * * prepare a command for the scsi physical devices. This rountine prepares * commands for devices which can take extended CDBs (>10 bytes) */static voidmegaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb, struct scsi_cmnd *scp){ mbox_ccb_t *ccb; mraid_epassthru_t *epthru; uint8_t channel; uint8_t target; ccb = (mbox_ccb_t *)scb->ccb; epthru = ccb->epthru; channel = scb->dev_channel; target = scb->dev_target; // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout epthru->timeout = 4; epthru->ars = 1; epthru->islogical = 0; epthru->channel = 0; epthru->target = (channel << 4) | target; epthru->logdrv = SCP2LUN(scp); epthru->reqsenselen = 14; epthru->cdblen = scp->cmd_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -