// routines to convert to and from the old the format staticint mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *); staticint kioc_to_mimd(uioc_t *, mimd_t __user *);
/* * Look for signature to see if this is the new or old ioctl format.
*/ if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) {
con_log(CL_ANN, (KERN_WARNING "megaraid cmm: copy from usr addr failed\n")); return (-EFAULT);
}
/* * At present, we don't support the new ioctl packet
*/ if (!old_ioctl ) return (-EINVAL);
/* * If it is a driver ioctl (as opposed to fw ioctls), then we can * handle the command locally. rval > 0 means it is not a drvr cmd
*/
rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval);
/* * Check if adapter can accept ioctl. We may have marked it offline * if any previous kioc had timedout on this controller.
*/ if (!adp->quiescent) {
con_log(CL_ANN, (KERN_WARNING "megaraid cmm: controller cannot accept cmds due to " "earlier errors\n" )); return -EFAULT;
}
/* * The following call will block till a kioc is available * or return NULL if the list head is empty for the pointer * of type mraid_mmapt passed to mraid_mm_alloc_kioc
*/
kioc = mraid_mm_alloc_kioc(adp); if (!kioc) return -ENXIO;
/* * User sent the old mimd_t ioctl packet. Convert it to uioc_t.
*/ if ((rval = mimd_to_kioc(argp, adp, kioc))) {
mraid_mm_dealloc_kioc(adp, kioc); return rval;
}
kioc->done = ioctl_done;
/* * Issue the IOCTL to the low level driver. After the IOCTL completes * release the kioc if and only if it was _not_ timedout. If it was * timedout, that means that resources are still with low level driver.
*/ if ((rval = lld_ioctl(adp, kioc))) {
if (!kioc->timedout)
mraid_mm_dealloc_kioc(adp, kioc);
return rval;
}
/* * Convert the kioc back to user space
*/
rval = kioc_to_mimd(kioc, argp);
/* * Return the kioc to free pool
*/
mraid_mm_dealloc_kioc(adp, kioc);
/** * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet * @umimd : User space mimd_t ioctl packet * @rval : returned success/error status * * The function return value is a pointer to the located @adapter.
*/ static mraid_mmadp_t *
mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
{
mraid_mmadp_t *adapter;
mimd_t mimd;
uint32_t adapno; int iterator; bool is_found;
/** * handle_drvrcmd - Checks if the opcode is a driver cmd and if it is, handles it. * @arg : packet sent by the user app * @old_ioctl : mimd if 1; uioc otherwise * @rval : pointer for command's returned value (not function status)
*/ staticint
handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval)
{
mimd_t __user *umimd;
mimd_t kmimd;
uint8_t opcode;
uint8_t subopcode;
if (old_ioctl) goto old_packet; else goto new_packet;
new_packet: return (-ENOTSUPP);
old_packet:
*rval = 0;
umimd = arg;
if (copy_from_user(&kmimd, umimd, sizeof(mimd_t))) return (-EFAULT);
/* * If the opcode is 0x82 and the subopcode is either GET_DRVRVER or * GET_NUMADP, then we can handle. Otherwise we should return 1 to * indicate that we cannot handle this.
*/ if (opcode != 0x82) return 1;
switch (subopcode) {
case MEGAIOC_QDRVRVER:
if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t))) return (-EFAULT);
return 0;
case MEGAIOC_QNADAP:
*rval = adapters_count_g;
if (copy_to_user(kmimd.data, &adapters_count_g, sizeof(uint32_t))) return (-EFAULT);
return 0;
default: /* cannot handle */ return 1;
}
return 0;
}
/** * mimd_to_kioc - Converter from old to new ioctl format * @umimd : user space old MIMD IOCTL * @adp : adapter softstate * @kioc : kernel space new format IOCTL * * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The * new packet is in kernel space so that driver can perform operations on it * freely.
*/
if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) return (-ENOMEM);
if (mimd.outlen) kioc->data_dir = UIOC_RD; if (mimd.inlen) kioc->data_dir |= UIOC_WR;
break;
default: return (-EINVAL);
}
/* * If driver command, nothing else to do
*/ if (opcode == 0x82) return 0;
/* * This is a mailbox cmd; copy the mailbox from mimd
*/
mbox64 = (mbox64_t *)((unsignedlong)kioc->cmdbuf);
mbox = &mbox64->mbox32;
memcpy(mbox, mimd.mbox, 14);
if (mbox->cmd != MBOXCMD_PASSTHRU) { // regular DCMD
mbox->xferaddr = (uint32_t)kioc->buf_paddr;
if (kioc->data_dir & UIOC_WR) { if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
kioc->xferlen)) { return (-EFAULT);
}
}
return 0;
}
/* * This is a regular 32-bit pthru cmd; mbox points to pthru struct. * Just like in above case, the beginning for memblk is treated as * a mailbox. The passthru will begin at next 1K boundary. And the * data will start 1K after that.
*/
pthru32 = kioc->pthru32;
kioc->user_pthru = &umimd->pthru;
mbox->xferaddr = (uint32_t)kioc->pthru32_h;
if (copy_from_user(pthru32, kioc->user_pthru, sizeof(mraid_passthru_t))) { return (-EFAULT);
}
pthru32->dataxferaddr = kioc->buf_paddr; if (kioc->data_dir & UIOC_WR) { if (pthru32->dataxferlen > kioc->xferlen) return -EINVAL; if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
pthru32->dataxferlen)) { return (-EFAULT);
}
}
return 0;
}
/** * mraid_mm_attach_buf - Attach a free dma buffer for required size * @adp : Adapter softstate * @kioc : kioc that the buffer needs to be attached to * @xferlen : required length for buffer * * First we search for a pool with smallest buffer that is >= @xferlen. If * that pool has no free buffer, we will try for the next bigger size. If none * is available, we will try to allocate the smallest buffer that is >= * @xferlen and attach it the pool.
*/ staticint
mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen)
{
mm_dmapool_t *pool; int right_pool = -1; unsignedlong flags; int i;
/* * If xferlen doesn't match any of our pools, return error
*/ if (right_pool == -1) return -EINVAL;
/* * We did not get any buffer from the preallocated pool. Let us try * to allocate one new buffer. NOTE: This is a blocking call.
*/
pool = &adp->dma_pool_list[right_pool];
/** * mraid_mm_alloc_kioc - Returns a uioc_t from free list * @adp : Adapter softstate for this module * * The kioc_semaphore is initialized with number of kioc nodes in the * free kioc pool. If the kioc pool is empty, this function blocks till * a kioc becomes free.
*/ static uioc_t *
mraid_mm_alloc_kioc(mraid_mmadp_t *adp)
{
uioc_t *kioc; struct list_head* head; unsignedlong flags;
down(&adp->kioc_semaphore);
spin_lock_irqsave(&adp->kioc_pool_lock, flags);
head = &adp->kioc_pool;
if (list_empty(head)) {
up(&adp->kioc_semaphore);
spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n")); return NULL;
}
/** * mraid_mm_dealloc_kioc - Return kioc to free pool * @adp : Adapter softstate * @kioc : uioc_t node to be returned to free pool
*/ staticvoid
mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc)
{
mm_dmapool_t *pool; unsignedlong flags;
if (kioc->pool_index != -1) {
pool = &adp->dma_pool_list[kioc->pool_index];
/* This routine may be called in non-isr context also */
spin_lock_irqsave(&pool->lock, flags);
/* * While attaching the dma buffer, if we didn't get the * required buffer from the pool, we would have allocated * it at the run time and set the free_buf flag. We must * free that buffer. Otherwise, just mark that the buffer is * not in use
*/ if (kioc->free_buf == 1)
dma_pool_free(pool->handle, kioc->buf_vaddr,
kioc->buf_paddr); else
pool->in_use = 0;
spin_unlock_irqrestore(&pool->lock, flags);
}
/* Return the kioc to the free pool */
spin_lock_irqsave(&adp->kioc_pool_lock, flags);
list_add(&kioc->list, &adp->kioc_pool);
spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
/* increment the free kioc count */
up(&adp->kioc_semaphore);
return;
}
/** * lld_ioctl - Routine to issue ioctl to low level drvr * @adp : The adapter handle * @kioc : The ioctl packet with kernel addresses
*/ staticint
lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
{ int rval; struct uioc_timeout timeout = { };
/* * Wait till the low level driver completes the ioctl. After this * call, the ioctl either completed successfully or timedout.
*/
wait_event(wait_q, (kioc->status != -ENODATA)); if (timeout.timer.function) {
timer_delete_sync(&timeout.timer);
timer_destroy_on_stack(&timeout.timer);
}
/* * If the command had timedout, we mark the controller offline * before returning
*/ if (kioc->timedout) {
adp->quiescent = 0;
}
return kioc->status;
}
/** * ioctl_done - callback from the low level driver * @kioc : completed ioctl packet
*/ staticvoid
ioctl_done(uioc_t *kioc)
{
uint32_t adapno; int iterator;
mraid_mmadp_t* adapter; bool is_found;
/* * When the kioc returns from driver, make sure it still doesn't * have ENODATA in status. Otherwise, driver will hang on wait_event * forever
*/ if (kioc->status == -ENODATA) {
con_log(CL_ANN, (KERN_WARNING "megaraid cmm: lld didn't change status!\n"));
kioc->status = -EINVAL;
}
/* * Check if this kioc was timedout before. If so, nobody is waiting * on this kioc. We don't have to wake up anybody. Instead, we just * have to free the kioc
*/ if (kioc->timedout) {
iterator = 0;
adapter = NULL;
adapno = kioc->adapno;
is_found = false;
con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed " "ioctl that was timedout before\n"));
/** * kioc_to_mimd - Converter from new back to old format * @kioc : Kernel space IOCTL packet (successfully issued) * @mimd : User space MIMD packet
*/ staticint
kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd)
{
mimd_t kmimd;
uint8_t opcode;
uint8_t subopcode;
if (copy_to_user(&upthru32->scsistatus,
&kpthru32->scsistatus, sizeof(uint8_t))) { return (-EFAULT);
}
}
if (kioc->user_data) { if (copy_to_user(kioc->user_data, kioc->buf_vaddr,
kioc->user_data_len)) { return (-EFAULT);
}
}
if (copy_to_user(&mimd->mbox[17],
&mbox64->mbox32.status, sizeof(uint8_t))) { return (-EFAULT);
}
return 0;
}
/** * hinfo_to_cinfo - Convert new format hba info into old format * @hinfo : New format, more comprehensive adapter info * @cinfo : Old format adapter info to support mimd_t apps
*/ staticvoid
hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo)
{ if (!hinfo || !cinfo) return;
/* * Allocate single blocks of memory for all required kiocs, * mailboxes and passthru structures.
*/
adapter->kioc_list = kmalloc_array(lld_adp->max_kioc, sizeof(uioc_t),
GFP_KERNEL);
adapter->mbox_list = kmalloc_array(lld_adp->max_kioc, sizeof(mbox64_t),
GFP_KERNEL);
adapter->pthru_dma_pool = dma_pool_create("megaraid mm pthru pool",
&adapter->pdev->dev, sizeof(mraid_passthru_t),
16, 0);
if (!adapter->kioc_list || !adapter->mbox_list ||
!adapter->pthru_dma_pool) {
con_log(CL_ANN, (KERN_WARNING "megaraid cmm: out of memory, %s %d\n", __func__,
__LINE__));
rval = (-ENOMEM);
goto memalloc_error;
}
/* * Slice kioc_list and make a kioc_pool with the individiual kiocs
*/
INIT_LIST_HEAD(&adapter->kioc_pool);
spin_lock_init(&adapter->kioc_pool_lock);
sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc);
/** * mraid_mm_adapter_app_handle - return the application handle for this adapter * @unique_id : adapter unique identifier * * For the given driver data, locate the adapter in our global list and * return the corresponding handle, which is also used by applications to * uniquely identify an adapter. * * Return adapter handle if found in the list. * Return 0 if adapter could not be located, should never happen though.
*/
uint32_t
mraid_mm_adapter_app_handle(uint32_t unique_id)
{
mraid_mmadp_t *adapter;
mraid_mmadp_t *tmp; int index = 0;
/** * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter * @adp : Adapter softstate * * We maintain a pool of dma buffers per each adapter. Each pool has one * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers. * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We * dont' want to waste too much memory by allocating more buffers per each * pool.
*/ staticint
mraid_mm_setup_dma_pools(mraid_mmadp_t *adp)
{
mm_dmapool_t *pool; int bufsize; int i;
/* * Create MAX_DMA_POOLS number of pools
*/
bufsize = MRAID_MM_INIT_BUFF_SIZE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.