📄 megaraid_mbox.c
字号:
if (unlikely(mbox->busy)) { do { udelay(1); i++; rmb(); } while(mbox->busy && (i < max_mbox_busy_wait)); if (mbox->busy) { spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); return -1; } } // Copy this command's mailbox data into "adapter's" mailbox memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22); mbox->cmdid = scb->sno; adapter->outstanding_cmds++; if (scb->dma_direction == PCI_DMA_TODEVICE) { if (!scb->scp->use_sg) { // sg list not used pci_dma_sync_single_for_device(adapter->pdev, ccb->buf_dma_h, scb->scp->request_bufflen, PCI_DMA_TODEVICE); } else { pci_dma_sync_sg_for_device(adapter->pdev, scb->scp->request_buffer, scb->scp->use_sg, PCI_DMA_TODEVICE); } } mbox->busy = 1; // Set busy mbox->poll = 0; mbox->ack = 0; wmb(); WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); return 0;}/** * megaraid_queue_command - generic queue entry point for all LLDs * @scp : pointer to the scsi command to be executed * @done : callback routine to be called after the cmd has be completed * * Queue entry point for mailbox based controllers. */static intmegaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *)){ adapter_t *adapter; scb_t *scb; int if_busy; adapter = SCP2ADAPTER(scp); scp->scsi_done = done; scp->result = 0; assert_spin_locked(adapter->host_lock); spin_unlock(adapter->host_lock); /* * Allocate and build a SCB request * if_busy flag will be set if megaraid_mbox_build_cmd() command could * not allocate scb. We will return non-zero status in that case. * NOTE: scb can be null even though certain commands completed * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would * return 0 in that case, and we would do the callback right away. */ if_busy = 0; scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy); if (scb) { megaraid_mbox_runpendq(adapter, scb); } spin_lock(adapter->host_lock); if (!scb) { // command already completed done(scp); return 0; } return if_busy;}/** * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid * firmware lingua * @adapter - controller's soft state * @scp - mid-layer scsi command pointer * @busy - set if request could not be completed because of lack of * resources * * 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -