18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci pf.c (c) 1997-8 Grant R. Guenther <grant@torque.net> 38c2ecf20Sopenharmony_ci Under the terms of the GNU General Public License. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci This is the high-level driver for parallel port ATAPI disk 68c2ecf20Sopenharmony_ci drives based on chips supported by the paride module. 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci By default, the driver will autoprobe for a single parallel 98c2ecf20Sopenharmony_ci port ATAPI disk drive, but if their individual parameters are 108c2ecf20Sopenharmony_ci specified, the driver can handle up to 4 drives. 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci The behaviour of the pf driver can be altered by setting 138c2ecf20Sopenharmony_ci some parameters from the insmod command line. The following 148c2ecf20Sopenharmony_ci parameters are adjustable: 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci drive0 These four arguments can be arrays of 178c2ecf20Sopenharmony_ci drive1 1-7 integers as follows: 188c2ecf20Sopenharmony_ci drive2 198c2ecf20Sopenharmony_ci drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<lun>,<dly> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci Where, 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci <prt> is the base of the parallel port address for 248c2ecf20Sopenharmony_ci the corresponding drive. (required) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci <pro> is the protocol number for the adapter that 278c2ecf20Sopenharmony_ci supports this drive. These numbers are 288c2ecf20Sopenharmony_ci logged by 'paride' when the protocol modules 298c2ecf20Sopenharmony_ci are initialised. (0 if not given) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci <uni> for those adapters that support chained 328c2ecf20Sopenharmony_ci devices, this is the unit selector for the 338c2ecf20Sopenharmony_ci chain of devices on the given port. It should 348c2ecf20Sopenharmony_ci be zero for devices that don't support chaining. 358c2ecf20Sopenharmony_ci (0 if not given) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci <mod> this can be -1 to choose the best mode, or one 388c2ecf20Sopenharmony_ci of the mode numbers supported by the adapter. 398c2ecf20Sopenharmony_ci (-1 if not given) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci <slv> ATAPI CDroms can be jumpered to master or slave. 428c2ecf20Sopenharmony_ci Set this to 0 to choose the master drive, 1 to 438c2ecf20Sopenharmony_ci choose the slave, -1 (the default) to choose the 448c2ecf20Sopenharmony_ci first drive found. 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci <lun> Some ATAPI devices support multiple LUNs. 478c2ecf20Sopenharmony_ci One example is the ATAPI PD/CD drive from 488c2ecf20Sopenharmony_ci Matshita/Panasonic. This device has a 498c2ecf20Sopenharmony_ci CD drive on LUN 0 and a PD drive on LUN 1. 508c2ecf20Sopenharmony_ci By default, the driver will search for the 518c2ecf20Sopenharmony_ci first LUN with a supported device. Set 528c2ecf20Sopenharmony_ci this parameter to force it to use a specific 538c2ecf20Sopenharmony_ci LUN. (default -1) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci <dly> some parallel ports require the driver to 568c2ecf20Sopenharmony_ci go more slowly. -1 sets a default value that 578c2ecf20Sopenharmony_ci should work with the chosen protocol. Otherwise, 588c2ecf20Sopenharmony_ci set this to a small integer, the larger it is 598c2ecf20Sopenharmony_ci the slower the port i/o. In some cases, setting 608c2ecf20Sopenharmony_ci this to zero will speed up the device. (default -1) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci major You may use this parameter to override the 638c2ecf20Sopenharmony_ci default major number (47) that this driver 648c2ecf20Sopenharmony_ci will use. Be sure to change the device 658c2ecf20Sopenharmony_ci name as well. 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci name This parameter is a character string that 688c2ecf20Sopenharmony_ci contains the name the kernel will use for this 698c2ecf20Sopenharmony_ci device (in /proc output, for instance). 708c2ecf20Sopenharmony_ci (default "pf"). 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci cluster The driver will attempt to aggregate requests 738c2ecf20Sopenharmony_ci for adjacent blocks into larger multi-block 748c2ecf20Sopenharmony_ci clusters. The maximum cluster size (in 512 758c2ecf20Sopenharmony_ci byte sectors) is set with this parameter. 768c2ecf20Sopenharmony_ci (default 64) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci verbose This parameter controls the amount of logging 798c2ecf20Sopenharmony_ci that the driver will do. Set it to 0 for 808c2ecf20Sopenharmony_ci normal operation, 1 to see autoprobe progress 818c2ecf20Sopenharmony_ci messages, or 2 to see additional debugging 828c2ecf20Sopenharmony_ci output. (default 0) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci nice This parameter controls the driver's use of 858c2ecf20Sopenharmony_ci idle CPU time, at the expense of some speed. 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci If this driver is built into the kernel, you can use the 888c2ecf20Sopenharmony_ci following command line parameters, with the same values 898c2ecf20Sopenharmony_ci as the corresponding module parameters listed above: 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci pf.drive0 928c2ecf20Sopenharmony_ci pf.drive1 938c2ecf20Sopenharmony_ci pf.drive2 948c2ecf20Sopenharmony_ci pf.drive3 958c2ecf20Sopenharmony_ci pf.cluster 968c2ecf20Sopenharmony_ci pf.nice 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci In addition, you can use the parameter pf.disable to disable 998c2ecf20Sopenharmony_ci the driver entirely. 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci*/ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* Changes: 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1.01 GRG 1998.05.03 Changes for SMP. Eliminate sti(). 1068c2ecf20Sopenharmony_ci Fix for drives that don't clear STAT_ERR 1078c2ecf20Sopenharmony_ci until after next CDB delivered. 1088c2ecf20Sopenharmony_ci Small change in pf_completion to round 1098c2ecf20Sopenharmony_ci up transfer size. 1108c2ecf20Sopenharmony_ci 1.02 GRG 1998.06.16 Eliminated an Ugh 1118c2ecf20Sopenharmony_ci 1.03 GRG 1998.08.16 Use HZ in loop timings, extra debugging 1128c2ecf20Sopenharmony_ci 1.04 GRG 1998.09.24 Added jumbo support 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci*/ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define PF_VERSION "1.04" 1178c2ecf20Sopenharmony_ci#define PF_MAJOR 47 1188c2ecf20Sopenharmony_ci#define PF_NAME "pf" 1198c2ecf20Sopenharmony_ci#define PF_UNITS 4 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#include <linux/types.h> 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* Here are things one can override from the insmod command. 1248c2ecf20Sopenharmony_ci Most are autoprobed by paride unless set here. Verbose is off 1258c2ecf20Sopenharmony_ci by default. 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci*/ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic bool verbose = 0; 1308c2ecf20Sopenharmony_cistatic int major = PF_MAJOR; 1318c2ecf20Sopenharmony_cistatic char *name = PF_NAME; 1328c2ecf20Sopenharmony_cistatic int cluster = 64; 1338c2ecf20Sopenharmony_cistatic int nice = 0; 1348c2ecf20Sopenharmony_cistatic int disable = 0; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int drive0[7] = { 0, 0, 0, -1, -1, -1, -1 }; 1378c2ecf20Sopenharmony_cistatic int drive1[7] = { 0, 0, 0, -1, -1, -1, -1 }; 1388c2ecf20Sopenharmony_cistatic int drive2[7] = { 0, 0, 0, -1, -1, -1, -1 }; 1398c2ecf20Sopenharmony_cistatic int drive3[7] = { 0, 0, 0, -1, -1, -1, -1 }; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int (*drives[4])[7] = {&drive0, &drive1, &drive2, &drive3}; 1428c2ecf20Sopenharmony_cistatic int pf_drive_count; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cienum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* end of parameters */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#include <linux/module.h> 1498c2ecf20Sopenharmony_ci#include <linux/init.h> 1508c2ecf20Sopenharmony_ci#include <linux/fs.h> 1518c2ecf20Sopenharmony_ci#include <linux/delay.h> 1528c2ecf20Sopenharmony_ci#include <linux/hdreg.h> 1538c2ecf20Sopenharmony_ci#include <linux/cdrom.h> 1548c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 1558c2ecf20Sopenharmony_ci#include <linux/blk-mq.h> 1568c2ecf20Sopenharmony_ci#include <linux/blkpg.h> 1578c2ecf20Sopenharmony_ci#include <linux/mutex.h> 1588c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(pf_mutex); 1618c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(pf_spin_lock); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cimodule_param(verbose, bool, 0644); 1648c2ecf20Sopenharmony_cimodule_param(major, int, 0); 1658c2ecf20Sopenharmony_cimodule_param(name, charp, 0); 1668c2ecf20Sopenharmony_cimodule_param(cluster, int, 0); 1678c2ecf20Sopenharmony_cimodule_param(nice, int, 0); 1688c2ecf20Sopenharmony_cimodule_param_array(drive0, int, NULL, 0); 1698c2ecf20Sopenharmony_cimodule_param_array(drive1, int, NULL, 0); 1708c2ecf20Sopenharmony_cimodule_param_array(drive2, int, NULL, 0); 1718c2ecf20Sopenharmony_cimodule_param_array(drive3, int, NULL, 0); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#include "paride.h" 1748c2ecf20Sopenharmony_ci#include "pseudo.h" 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* constants for faking geometry numbers */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#define PF_FD_MAX 8192 /* use FD geometry under this size */ 1798c2ecf20Sopenharmony_ci#define PF_FD_HDS 2 1808c2ecf20Sopenharmony_ci#define PF_FD_SPT 18 1818c2ecf20Sopenharmony_ci#define PF_HD_HDS 64 1828c2ecf20Sopenharmony_ci#define PF_HD_SPT 32 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define PF_MAX_RETRIES 5 1858c2ecf20Sopenharmony_ci#define PF_TMO 800 /* interrupt timeout in jiffies */ 1868c2ecf20Sopenharmony_ci#define PF_SPIN_DEL 50 /* spin delay in micro-seconds */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define PF_SPIN (1000000*PF_TMO)/(HZ*PF_SPIN_DEL) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define STAT_ERR 0x00001 1918c2ecf20Sopenharmony_ci#define STAT_INDEX 0x00002 1928c2ecf20Sopenharmony_ci#define STAT_ECC 0x00004 1938c2ecf20Sopenharmony_ci#define STAT_DRQ 0x00008 1948c2ecf20Sopenharmony_ci#define STAT_SEEK 0x00010 1958c2ecf20Sopenharmony_ci#define STAT_WRERR 0x00020 1968c2ecf20Sopenharmony_ci#define STAT_READY 0x00040 1978c2ecf20Sopenharmony_ci#define STAT_BUSY 0x00080 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#define ATAPI_REQ_SENSE 0x03 2008c2ecf20Sopenharmony_ci#define ATAPI_LOCK 0x1e 2018c2ecf20Sopenharmony_ci#define ATAPI_DOOR 0x1b 2028c2ecf20Sopenharmony_ci#define ATAPI_MODE_SENSE 0x5a 2038c2ecf20Sopenharmony_ci#define ATAPI_CAPACITY 0x25 2048c2ecf20Sopenharmony_ci#define ATAPI_IDENTIFY 0x12 2058c2ecf20Sopenharmony_ci#define ATAPI_READ_10 0x28 2068c2ecf20Sopenharmony_ci#define ATAPI_WRITE_10 0x2a 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int pf_open(struct block_device *bdev, fmode_t mode); 2098c2ecf20Sopenharmony_cistatic blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx, 2108c2ecf20Sopenharmony_ci const struct blk_mq_queue_data *bd); 2118c2ecf20Sopenharmony_cistatic int pf_ioctl(struct block_device *bdev, fmode_t mode, 2128c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg); 2138c2ecf20Sopenharmony_cistatic int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void pf_release(struct gendisk *disk, fmode_t mode); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int pf_detect(void); 2188c2ecf20Sopenharmony_cistatic void do_pf_read(void); 2198c2ecf20Sopenharmony_cistatic void do_pf_read_start(void); 2208c2ecf20Sopenharmony_cistatic void do_pf_write(void); 2218c2ecf20Sopenharmony_cistatic void do_pf_write_start(void); 2228c2ecf20Sopenharmony_cistatic void do_pf_read_drq(void); 2238c2ecf20Sopenharmony_cistatic void do_pf_write_done(void); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci#define PF_NM 0 2268c2ecf20Sopenharmony_ci#define PF_RO 1 2278c2ecf20Sopenharmony_ci#define PF_RW 2 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define PF_NAMELEN 8 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistruct pf_unit { 2328c2ecf20Sopenharmony_ci struct pi_adapter pia; /* interface to paride layer */ 2338c2ecf20Sopenharmony_ci struct pi_adapter *pi; 2348c2ecf20Sopenharmony_ci int removable; /* removable media device ? */ 2358c2ecf20Sopenharmony_ci int media_status; /* media present ? WP ? */ 2368c2ecf20Sopenharmony_ci int drive; /* drive */ 2378c2ecf20Sopenharmony_ci int lun; 2388c2ecf20Sopenharmony_ci int access; /* count of active opens ... */ 2398c2ecf20Sopenharmony_ci int present; /* device present ? */ 2408c2ecf20Sopenharmony_ci char name[PF_NAMELEN]; /* pf0, pf1, ... */ 2418c2ecf20Sopenharmony_ci struct gendisk *disk; 2428c2ecf20Sopenharmony_ci struct blk_mq_tag_set tag_set; 2438c2ecf20Sopenharmony_ci struct list_head rq_list; 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct pf_unit units[PF_UNITS]; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int pf_identify(struct pf_unit *pf); 2498c2ecf20Sopenharmony_cistatic void pf_lock(struct pf_unit *pf, int func); 2508c2ecf20Sopenharmony_cistatic void pf_eject(struct pf_unit *pf); 2518c2ecf20Sopenharmony_cistatic unsigned int pf_check_events(struct gendisk *disk, 2528c2ecf20Sopenharmony_ci unsigned int clearing); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic char pf_scratch[512]; /* scratch block buffer */ 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* the variables below are used mainly in the I/O request engine, which 2578c2ecf20Sopenharmony_ci processes only one request at a time. 2588c2ecf20Sopenharmony_ci*/ 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int pf_retries = 0; /* i/o error retry count */ 2618c2ecf20Sopenharmony_cistatic int pf_busy = 0; /* request being processed ? */ 2628c2ecf20Sopenharmony_cistatic struct request *pf_req; /* current request */ 2638c2ecf20Sopenharmony_cistatic int pf_block; /* address of next requested block */ 2648c2ecf20Sopenharmony_cistatic int pf_count; /* number of blocks still to do */ 2658c2ecf20Sopenharmony_cistatic int pf_run; /* sectors in current cluster */ 2668c2ecf20Sopenharmony_cistatic int pf_cmd; /* current command READ/WRITE */ 2678c2ecf20Sopenharmony_cistatic struct pf_unit *pf_current;/* unit of current request */ 2688c2ecf20Sopenharmony_cistatic int pf_mask; /* stopper for pseudo-int */ 2698c2ecf20Sopenharmony_cistatic char *pf_buf; /* buffer for request in progress */ 2708c2ecf20Sopenharmony_cistatic void *par_drv; /* reference of parport driver */ 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* kernel glue structures */ 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic const struct block_device_operations pf_fops = { 2758c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2768c2ecf20Sopenharmony_ci .open = pf_open, 2778c2ecf20Sopenharmony_ci .release = pf_release, 2788c2ecf20Sopenharmony_ci .ioctl = pf_ioctl, 2798c2ecf20Sopenharmony_ci .compat_ioctl = pf_ioctl, 2808c2ecf20Sopenharmony_ci .getgeo = pf_getgeo, 2818c2ecf20Sopenharmony_ci .check_events = pf_check_events, 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const struct blk_mq_ops pf_mq_ops = { 2858c2ecf20Sopenharmony_ci .queue_rq = pf_queue_rq, 2868c2ecf20Sopenharmony_ci}; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void __init pf_init_units(void) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct pf_unit *pf; 2918c2ecf20Sopenharmony_ci int unit; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci pf_drive_count = 0; 2948c2ecf20Sopenharmony_ci for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) { 2958c2ecf20Sopenharmony_ci struct gendisk *disk; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci disk = alloc_disk(1); 2988c2ecf20Sopenharmony_ci if (!disk) 2998c2ecf20Sopenharmony_ci continue; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci disk->queue = blk_mq_init_sq_queue(&pf->tag_set, &pf_mq_ops, 3028c2ecf20Sopenharmony_ci 1, BLK_MQ_F_SHOULD_MERGE); 3038c2ecf20Sopenharmony_ci if (IS_ERR(disk->queue)) { 3048c2ecf20Sopenharmony_ci disk->queue = NULL; 3058c2ecf20Sopenharmony_ci put_disk(disk); 3068c2ecf20Sopenharmony_ci continue; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pf->rq_list); 3108c2ecf20Sopenharmony_ci disk->queue->queuedata = pf; 3118c2ecf20Sopenharmony_ci blk_queue_max_segments(disk->queue, cluster); 3128c2ecf20Sopenharmony_ci blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH); 3138c2ecf20Sopenharmony_ci pf->disk = disk; 3148c2ecf20Sopenharmony_ci pf->pi = &pf->pia; 3158c2ecf20Sopenharmony_ci pf->media_status = PF_NM; 3168c2ecf20Sopenharmony_ci pf->drive = (*drives[unit])[D_SLV]; 3178c2ecf20Sopenharmony_ci pf->lun = (*drives[unit])[D_LUN]; 3188c2ecf20Sopenharmony_ci snprintf(pf->name, PF_NAMELEN, "%s%d", name, unit); 3198c2ecf20Sopenharmony_ci disk->major = major; 3208c2ecf20Sopenharmony_ci disk->first_minor = unit; 3218c2ecf20Sopenharmony_ci strcpy(disk->disk_name, pf->name); 3228c2ecf20Sopenharmony_ci disk->fops = &pf_fops; 3238c2ecf20Sopenharmony_ci disk->events = DISK_EVENT_MEDIA_CHANGE; 3248c2ecf20Sopenharmony_ci if (!(*drives[unit])[D_PRT]) 3258c2ecf20Sopenharmony_ci pf_drive_count++; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int pf_open(struct block_device *bdev, fmode_t mode) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct pf_unit *pf = bdev->bd_disk->private_data; 3328c2ecf20Sopenharmony_ci int ret; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci mutex_lock(&pf_mutex); 3358c2ecf20Sopenharmony_ci pf_identify(pf); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ret = -ENODEV; 3388c2ecf20Sopenharmony_ci if (pf->media_status == PF_NM) 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = -EROFS; 3428c2ecf20Sopenharmony_ci if ((pf->media_status == PF_RO) && (mode & FMODE_WRITE)) 3438c2ecf20Sopenharmony_ci goto out; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci ret = 0; 3468c2ecf20Sopenharmony_ci pf->access++; 3478c2ecf20Sopenharmony_ci if (pf->removable) 3488c2ecf20Sopenharmony_ci pf_lock(pf, 1); 3498c2ecf20Sopenharmony_ciout: 3508c2ecf20Sopenharmony_ci mutex_unlock(&pf_mutex); 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct pf_unit *pf = bdev->bd_disk->private_data; 3578c2ecf20Sopenharmony_ci sector_t capacity = get_capacity(pf->disk); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (capacity < PF_FD_MAX) { 3608c2ecf20Sopenharmony_ci geo->cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT); 3618c2ecf20Sopenharmony_ci geo->heads = PF_FD_HDS; 3628c2ecf20Sopenharmony_ci geo->sectors = PF_FD_SPT; 3638c2ecf20Sopenharmony_ci } else { 3648c2ecf20Sopenharmony_ci geo->cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT); 3658c2ecf20Sopenharmony_ci geo->heads = PF_HD_HDS; 3668c2ecf20Sopenharmony_ci geo->sectors = PF_HD_SPT; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int pf_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct pf_unit *pf = bdev->bd_disk->private_data; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (cmd != CDROMEJECT) 3778c2ecf20Sopenharmony_ci return -EINVAL; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (pf->access != 1) 3808c2ecf20Sopenharmony_ci return -EBUSY; 3818c2ecf20Sopenharmony_ci mutex_lock(&pf_mutex); 3828c2ecf20Sopenharmony_ci pf_eject(pf); 3838c2ecf20Sopenharmony_ci mutex_unlock(&pf_mutex); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void pf_release(struct gendisk *disk, fmode_t mode) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct pf_unit *pf = disk->private_data; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci mutex_lock(&pf_mutex); 3938c2ecf20Sopenharmony_ci if (pf->access <= 0) { 3948c2ecf20Sopenharmony_ci mutex_unlock(&pf_mutex); 3958c2ecf20Sopenharmony_ci WARN_ON(1); 3968c2ecf20Sopenharmony_ci return; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci pf->access--; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (!pf->access && pf->removable) 4028c2ecf20Sopenharmony_ci pf_lock(pf, 0); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci mutex_unlock(&pf_mutex); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic unsigned int pf_check_events(struct gendisk *disk, unsigned int clearing) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci return DISK_EVENT_MEDIA_CHANGE; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic inline int status_reg(struct pf_unit *pf) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci return pi_read_regr(pf->pi, 1, 6); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic inline int read_reg(struct pf_unit *pf, int reg) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return pi_read_regr(pf->pi, 0, reg); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic inline void write_reg(struct pf_unit *pf, int reg, int val) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci pi_write_regr(pf->pi, 0, reg, val); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int pf_wait(struct pf_unit *pf, int go, int stop, char *fun, char *msg) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci int j, r, e, s, p; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci j = 0; 4328c2ecf20Sopenharmony_ci while ((((r = status_reg(pf)) & go) || (stop && (!(r & stop)))) 4338c2ecf20Sopenharmony_ci && (j++ < PF_SPIN)) 4348c2ecf20Sopenharmony_ci udelay(PF_SPIN_DEL); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if ((r & (STAT_ERR & stop)) || (j > PF_SPIN)) { 4378c2ecf20Sopenharmony_ci s = read_reg(pf, 7); 4388c2ecf20Sopenharmony_ci e = read_reg(pf, 1); 4398c2ecf20Sopenharmony_ci p = read_reg(pf, 2); 4408c2ecf20Sopenharmony_ci if (j > PF_SPIN) 4418c2ecf20Sopenharmony_ci e |= 0x100; 4428c2ecf20Sopenharmony_ci if (fun) 4438c2ecf20Sopenharmony_ci printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x" 4448c2ecf20Sopenharmony_ci " loop=%d phase=%d\n", 4458c2ecf20Sopenharmony_ci pf->name, fun, msg, r, s, e, j, p); 4468c2ecf20Sopenharmony_ci return (e << 8) + s; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int pf_command(struct pf_unit *pf, char *cmd, int dlen, char *fun) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci pi_connect(pf->pi); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci write_reg(pf, 6, 0xa0+0x10*pf->drive); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (pf_wait(pf, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) { 4588c2ecf20Sopenharmony_ci pi_disconnect(pf->pi); 4598c2ecf20Sopenharmony_ci return -1; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci write_reg(pf, 4, dlen % 256); 4638c2ecf20Sopenharmony_ci write_reg(pf, 5, dlen / 256); 4648c2ecf20Sopenharmony_ci write_reg(pf, 7, 0xa0); /* ATAPI packet command */ 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (pf_wait(pf, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) { 4678c2ecf20Sopenharmony_ci pi_disconnect(pf->pi); 4688c2ecf20Sopenharmony_ci return -1; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (read_reg(pf, 2) != 1) { 4728c2ecf20Sopenharmony_ci printk("%s: %s: command phase error\n", pf->name, fun); 4738c2ecf20Sopenharmony_ci pi_disconnect(pf->pi); 4748c2ecf20Sopenharmony_ci return -1; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci pi_write_block(pf->pi, cmd, 12); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int pf_completion(struct pf_unit *pf, char *buf, char *fun) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci int r, s, n; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci r = pf_wait(pf, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR, 4878c2ecf20Sopenharmony_ci fun, "completion"); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if ((read_reg(pf, 2) & 2) && (read_reg(pf, 7) & STAT_DRQ)) { 4908c2ecf20Sopenharmony_ci n = (((read_reg(pf, 4) + 256 * read_reg(pf, 5)) + 4918c2ecf20Sopenharmony_ci 3) & 0xfffc); 4928c2ecf20Sopenharmony_ci pi_read_block(pf->pi, buf, n); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci s = pf_wait(pf, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done"); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci pi_disconnect(pf->pi); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return (r ? r : s); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic void pf_req_sense(struct pf_unit *pf, int quiet) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci char rs_cmd[12] = 5058c2ecf20Sopenharmony_ci { ATAPI_REQ_SENSE, pf->lun << 5, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 }; 5068c2ecf20Sopenharmony_ci char buf[16]; 5078c2ecf20Sopenharmony_ci int r; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci r = pf_command(pf, rs_cmd, 16, "Request sense"); 5108c2ecf20Sopenharmony_ci mdelay(1); 5118c2ecf20Sopenharmony_ci if (!r) 5128c2ecf20Sopenharmony_ci pf_completion(pf, buf, "Request sense"); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if ((!r) && (!quiet)) 5158c2ecf20Sopenharmony_ci printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n", 5168c2ecf20Sopenharmony_ci pf->name, buf[2] & 0xf, buf[12], buf[13]); 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int pf_atapi(struct pf_unit *pf, char *cmd, int dlen, char *buf, char *fun) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci int r; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci r = pf_command(pf, cmd, dlen, fun); 5248c2ecf20Sopenharmony_ci mdelay(1); 5258c2ecf20Sopenharmony_ci if (!r) 5268c2ecf20Sopenharmony_ci r = pf_completion(pf, buf, fun); 5278c2ecf20Sopenharmony_ci if (r) 5288c2ecf20Sopenharmony_ci pf_req_sense(pf, !fun); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return r; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic void pf_lock(struct pf_unit *pf, int func) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci char lo_cmd[12] = { ATAPI_LOCK, pf->lun << 5, 0, 0, func, 0, 0, 0, 0, 0, 0, 0 }; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "lock" : "unlock"); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic void pf_eject(struct pf_unit *pf) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci char ej_cmd[12] = { ATAPI_DOOR, pf->lun << 5, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci pf_lock(pf, 0); 5458c2ecf20Sopenharmony_ci pf_atapi(pf, ej_cmd, 0, pf_scratch, "eject"); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci#define PF_RESET_TMO 30 /* in tenths of a second */ 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void pf_sleep(int cs) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci schedule_timeout_interruptible(cs); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/* the ATAPI standard actually specifies the contents of all 7 registers 5568c2ecf20Sopenharmony_ci after a reset, but the specification is ambiguous concerning the last 5578c2ecf20Sopenharmony_ci two bytes, and different drives interpret the standard differently. 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int pf_reset(struct pf_unit *pf) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci int i, k, flg; 5638c2ecf20Sopenharmony_ci int expect[5] = { 1, 1, 1, 0x14, 0xeb }; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci pi_connect(pf->pi); 5668c2ecf20Sopenharmony_ci write_reg(pf, 6, 0xa0+0x10*pf->drive); 5678c2ecf20Sopenharmony_ci write_reg(pf, 7, 8); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci pf_sleep(20 * HZ / 1000); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci k = 0; 5728c2ecf20Sopenharmony_ci while ((k++ < PF_RESET_TMO) && (status_reg(pf) & STAT_BUSY)) 5738c2ecf20Sopenharmony_ci pf_sleep(HZ / 10); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci flg = 1; 5768c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) 5778c2ecf20Sopenharmony_ci flg &= (read_reg(pf, i + 1) == expect[i]); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (verbose) { 5808c2ecf20Sopenharmony_ci printk("%s: Reset (%d) signature = ", pf->name, k); 5818c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) 5828c2ecf20Sopenharmony_ci printk("%3x", read_reg(pf, i + 1)); 5838c2ecf20Sopenharmony_ci if (!flg) 5848c2ecf20Sopenharmony_ci printk(" (incorrect)"); 5858c2ecf20Sopenharmony_ci printk("\n"); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci pi_disconnect(pf->pi); 5898c2ecf20Sopenharmony_ci return flg - 1; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic void pf_mode_sense(struct pf_unit *pf) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci char ms_cmd[12] = 5958c2ecf20Sopenharmony_ci { ATAPI_MODE_SENSE, pf->lun << 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 }; 5968c2ecf20Sopenharmony_ci char buf[8]; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci pf_atapi(pf, ms_cmd, 8, buf, "mode sense"); 5998c2ecf20Sopenharmony_ci pf->media_status = PF_RW; 6008c2ecf20Sopenharmony_ci if (buf[3] & 0x80) 6018c2ecf20Sopenharmony_ci pf->media_status = PF_RO; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic void xs(char *buf, char *targ, int offs, int len) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci int j, k, l; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci j = 0; 6098c2ecf20Sopenharmony_ci l = 0; 6108c2ecf20Sopenharmony_ci for (k = 0; k < len; k++) 6118c2ecf20Sopenharmony_ci if ((buf[k + offs] != 0x20) || (buf[k + offs] != l)) 6128c2ecf20Sopenharmony_ci l = targ[j++] = buf[k + offs]; 6138c2ecf20Sopenharmony_ci if (l == 0x20) 6148c2ecf20Sopenharmony_ci j--; 6158c2ecf20Sopenharmony_ci targ[j] = 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int xl(char *buf, int offs) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci int v, k; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci v = 0; 6238c2ecf20Sopenharmony_ci for (k = 0; k < 4; k++) 6248c2ecf20Sopenharmony_ci v = v * 256 + (buf[k + offs] & 0xff); 6258c2ecf20Sopenharmony_ci return v; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic void pf_get_capacity(struct pf_unit *pf) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci char rc_cmd[12] = { ATAPI_CAPACITY, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 6318c2ecf20Sopenharmony_ci char buf[8]; 6328c2ecf20Sopenharmony_ci int bs; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (pf_atapi(pf, rc_cmd, 8, buf, "get capacity")) { 6358c2ecf20Sopenharmony_ci pf->media_status = PF_NM; 6368c2ecf20Sopenharmony_ci return; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci set_capacity(pf->disk, xl(buf, 0) + 1); 6398c2ecf20Sopenharmony_ci bs = xl(buf, 4); 6408c2ecf20Sopenharmony_ci if (bs != 512) { 6418c2ecf20Sopenharmony_ci set_capacity(pf->disk, 0); 6428c2ecf20Sopenharmony_ci if (verbose) 6438c2ecf20Sopenharmony_ci printk("%s: Drive %d, LUN %d," 6448c2ecf20Sopenharmony_ci " unsupported block size %d\n", 6458c2ecf20Sopenharmony_ci pf->name, pf->drive, pf->lun, bs); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic int pf_identify(struct pf_unit *pf) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci int dt, s; 6528c2ecf20Sopenharmony_ci char *ms[2] = { "master", "slave" }; 6538c2ecf20Sopenharmony_ci char mf[10], id[18]; 6548c2ecf20Sopenharmony_ci char id_cmd[12] = 6558c2ecf20Sopenharmony_ci { ATAPI_IDENTIFY, pf->lun << 5, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; 6568c2ecf20Sopenharmony_ci char buf[36]; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci s = pf_atapi(pf, id_cmd, 36, buf, "identify"); 6598c2ecf20Sopenharmony_ci if (s) 6608c2ecf20Sopenharmony_ci return -1; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci dt = buf[0] & 0x1f; 6638c2ecf20Sopenharmony_ci if ((dt != 0) && (dt != 7)) { 6648c2ecf20Sopenharmony_ci if (verbose) 6658c2ecf20Sopenharmony_ci printk("%s: Drive %d, LUN %d, unsupported type %d\n", 6668c2ecf20Sopenharmony_ci pf->name, pf->drive, pf->lun, dt); 6678c2ecf20Sopenharmony_ci return -1; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci xs(buf, mf, 8, 8); 6718c2ecf20Sopenharmony_ci xs(buf, id, 16, 16); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci pf->removable = (buf[1] & 0x80); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci pf_mode_sense(pf); 6768c2ecf20Sopenharmony_ci pf_mode_sense(pf); 6778c2ecf20Sopenharmony_ci pf_mode_sense(pf); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci pf_get_capacity(pf); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci printk("%s: %s %s, %s LUN %d, type %d", 6828c2ecf20Sopenharmony_ci pf->name, mf, id, ms[pf->drive], pf->lun, dt); 6838c2ecf20Sopenharmony_ci if (pf->removable) 6848c2ecf20Sopenharmony_ci printk(", removable"); 6858c2ecf20Sopenharmony_ci if (pf->media_status == PF_NM) 6868c2ecf20Sopenharmony_ci printk(", no media\n"); 6878c2ecf20Sopenharmony_ci else { 6888c2ecf20Sopenharmony_ci if (pf->media_status == PF_RO) 6898c2ecf20Sopenharmony_ci printk(", RO"); 6908c2ecf20Sopenharmony_ci printk(", %llu blocks\n", 6918c2ecf20Sopenharmony_ci (unsigned long long)get_capacity(pf->disk)); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/* returns 0, with id set if drive is detected 6978c2ecf20Sopenharmony_ci -1, if drive detection failed 6988c2ecf20Sopenharmony_ci*/ 6998c2ecf20Sopenharmony_cistatic int pf_probe(struct pf_unit *pf) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci if (pf->drive == -1) { 7028c2ecf20Sopenharmony_ci for (pf->drive = 0; pf->drive <= 1; pf->drive++) 7038c2ecf20Sopenharmony_ci if (!pf_reset(pf)) { 7048c2ecf20Sopenharmony_ci if (pf->lun != -1) 7058c2ecf20Sopenharmony_ci return pf_identify(pf); 7068c2ecf20Sopenharmony_ci else 7078c2ecf20Sopenharmony_ci for (pf->lun = 0; pf->lun < 8; pf->lun++) 7088c2ecf20Sopenharmony_ci if (!pf_identify(pf)) 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci } else { 7128c2ecf20Sopenharmony_ci if (pf_reset(pf)) 7138c2ecf20Sopenharmony_ci return -1; 7148c2ecf20Sopenharmony_ci if (pf->lun != -1) 7158c2ecf20Sopenharmony_ci return pf_identify(pf); 7168c2ecf20Sopenharmony_ci for (pf->lun = 0; pf->lun < 8; pf->lun++) 7178c2ecf20Sopenharmony_ci if (!pf_identify(pf)) 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci return -1; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int pf_detect(void) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct pf_unit *pf = units; 7268c2ecf20Sopenharmony_ci int k, unit; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci printk("%s: %s version %s, major %d, cluster %d, nice %d\n", 7298c2ecf20Sopenharmony_ci name, name, PF_VERSION, major, cluster, nice); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci par_drv = pi_register_driver(name); 7328c2ecf20Sopenharmony_ci if (!par_drv) { 7338c2ecf20Sopenharmony_ci pr_err("failed to register %s driver\n", name); 7348c2ecf20Sopenharmony_ci return -1; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci k = 0; 7378c2ecf20Sopenharmony_ci if (pf_drive_count == 0) { 7388c2ecf20Sopenharmony_ci if (pi_init(pf->pi, 1, -1, -1, -1, -1, -1, pf_scratch, PI_PF, 7398c2ecf20Sopenharmony_ci verbose, pf->name)) { 7408c2ecf20Sopenharmony_ci if (!pf_probe(pf) && pf->disk) { 7418c2ecf20Sopenharmony_ci pf->present = 1; 7428c2ecf20Sopenharmony_ci k++; 7438c2ecf20Sopenharmony_ci } else 7448c2ecf20Sopenharmony_ci pi_release(pf->pi); 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci } else 7488c2ecf20Sopenharmony_ci for (unit = 0; unit < PF_UNITS; unit++, pf++) { 7498c2ecf20Sopenharmony_ci int *conf = *drives[unit]; 7508c2ecf20Sopenharmony_ci if (!conf[D_PRT]) 7518c2ecf20Sopenharmony_ci continue; 7528c2ecf20Sopenharmony_ci if (pi_init(pf->pi, 0, conf[D_PRT], conf[D_MOD], 7538c2ecf20Sopenharmony_ci conf[D_UNI], conf[D_PRO], conf[D_DLY], 7548c2ecf20Sopenharmony_ci pf_scratch, PI_PF, verbose, pf->name)) { 7558c2ecf20Sopenharmony_ci if (pf->disk && !pf_probe(pf)) { 7568c2ecf20Sopenharmony_ci pf->present = 1; 7578c2ecf20Sopenharmony_ci k++; 7588c2ecf20Sopenharmony_ci } else 7598c2ecf20Sopenharmony_ci pi_release(pf->pi); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci if (k) 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci printk("%s: No ATAPI disk detected\n", name); 7668c2ecf20Sopenharmony_ci for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { 7678c2ecf20Sopenharmony_ci if (!pf->disk) 7688c2ecf20Sopenharmony_ci continue; 7698c2ecf20Sopenharmony_ci blk_cleanup_queue(pf->disk->queue); 7708c2ecf20Sopenharmony_ci pf->disk->queue = NULL; 7718c2ecf20Sopenharmony_ci blk_mq_free_tag_set(&pf->tag_set); 7728c2ecf20Sopenharmony_ci put_disk(pf->disk); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci pi_unregister_driver(par_drv); 7758c2ecf20Sopenharmony_ci return -1; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci/* The i/o request engine */ 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic int pf_start(struct pf_unit *pf, int cmd, int b, int c) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci int i; 7838c2ecf20Sopenharmony_ci char io_cmd[12] = { cmd, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 7868c2ecf20Sopenharmony_ci io_cmd[5 - i] = b & 0xff; 7878c2ecf20Sopenharmony_ci b = b >> 8; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci io_cmd[8] = c & 0xff; 7918c2ecf20Sopenharmony_ci io_cmd[7] = (c >> 8) & 0xff; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci i = pf_command(pf, io_cmd, c * 512, "start i/o"); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci mdelay(1); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci return i; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic int pf_ready(void) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask)); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic int pf_queue; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int set_next_request(void) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct pf_unit *pf; 8108c2ecf20Sopenharmony_ci int old_pos = pf_queue; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci do { 8138c2ecf20Sopenharmony_ci pf = &units[pf_queue]; 8148c2ecf20Sopenharmony_ci if (++pf_queue == PF_UNITS) 8158c2ecf20Sopenharmony_ci pf_queue = 0; 8168c2ecf20Sopenharmony_ci if (pf->present && !list_empty(&pf->rq_list)) { 8178c2ecf20Sopenharmony_ci pf_req = list_first_entry(&pf->rq_list, struct request, 8188c2ecf20Sopenharmony_ci queuelist); 8198c2ecf20Sopenharmony_ci list_del_init(&pf_req->queuelist); 8208c2ecf20Sopenharmony_ci blk_mq_start_request(pf_req); 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci } while (pf_queue != old_pos); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return pf_req != NULL; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic void pf_end_request(blk_status_t err) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci if (!pf_req) 8318c2ecf20Sopenharmony_ci return; 8328c2ecf20Sopenharmony_ci if (!blk_update_request(pf_req, err, blk_rq_cur_bytes(pf_req))) { 8338c2ecf20Sopenharmony_ci __blk_mq_end_request(pf_req, err); 8348c2ecf20Sopenharmony_ci pf_req = NULL; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic void pf_request(void) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci if (pf_busy) 8418c2ecf20Sopenharmony_ci return; 8428c2ecf20Sopenharmony_cirepeat: 8438c2ecf20Sopenharmony_ci if (!pf_req && !set_next_request()) 8448c2ecf20Sopenharmony_ci return; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci pf_current = pf_req->rq_disk->private_data; 8478c2ecf20Sopenharmony_ci pf_block = blk_rq_pos(pf_req); 8488c2ecf20Sopenharmony_ci pf_run = blk_rq_sectors(pf_req); 8498c2ecf20Sopenharmony_ci pf_count = blk_rq_cur_sectors(pf_req); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { 8528c2ecf20Sopenharmony_ci pf_end_request(BLK_STS_IOERR); 8538c2ecf20Sopenharmony_ci goto repeat; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci pf_cmd = rq_data_dir(pf_req); 8578c2ecf20Sopenharmony_ci pf_buf = bio_data(pf_req->bio); 8588c2ecf20Sopenharmony_ci pf_retries = 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci pf_busy = 1; 8618c2ecf20Sopenharmony_ci if (pf_cmd == READ) 8628c2ecf20Sopenharmony_ci pi_do_claimed(pf_current->pi, do_pf_read); 8638c2ecf20Sopenharmony_ci else if (pf_cmd == WRITE) 8648c2ecf20Sopenharmony_ci pi_do_claimed(pf_current->pi, do_pf_write); 8658c2ecf20Sopenharmony_ci else { 8668c2ecf20Sopenharmony_ci pf_busy = 0; 8678c2ecf20Sopenharmony_ci pf_end_request(BLK_STS_IOERR); 8688c2ecf20Sopenharmony_ci goto repeat; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx, 8738c2ecf20Sopenharmony_ci const struct blk_mq_queue_data *bd) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct pf_unit *pf = hctx->queue->queuedata; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci spin_lock_irq(&pf_spin_lock); 8788c2ecf20Sopenharmony_ci list_add_tail(&bd->rq->queuelist, &pf->rq_list); 8798c2ecf20Sopenharmony_ci pf_request(); 8808c2ecf20Sopenharmony_ci spin_unlock_irq(&pf_spin_lock); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci return BLK_STS_OK; 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic int pf_next_buf(void) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci unsigned long saved_flags; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci pf_count--; 8908c2ecf20Sopenharmony_ci pf_run--; 8918c2ecf20Sopenharmony_ci pf_buf += 512; 8928c2ecf20Sopenharmony_ci pf_block++; 8938c2ecf20Sopenharmony_ci if (!pf_run) 8948c2ecf20Sopenharmony_ci return 1; 8958c2ecf20Sopenharmony_ci if (!pf_count) { 8968c2ecf20Sopenharmony_ci spin_lock_irqsave(&pf_spin_lock, saved_flags); 8978c2ecf20Sopenharmony_ci pf_end_request(0); 8988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pf_spin_lock, saved_flags); 8998c2ecf20Sopenharmony_ci if (!pf_req) 9008c2ecf20Sopenharmony_ci return 1; 9018c2ecf20Sopenharmony_ci pf_count = blk_rq_cur_sectors(pf_req); 9028c2ecf20Sopenharmony_ci pf_buf = bio_data(pf_req->bio); 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic inline void next_request(blk_status_t err) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci unsigned long saved_flags; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci spin_lock_irqsave(&pf_spin_lock, saved_flags); 9128c2ecf20Sopenharmony_ci pf_end_request(err); 9138c2ecf20Sopenharmony_ci pf_busy = 0; 9148c2ecf20Sopenharmony_ci pf_request(); 9158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pf_spin_lock, saved_flags); 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/* detach from the calling context - in case the spinlock is held */ 9198c2ecf20Sopenharmony_cistatic void do_pf_read(void) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci ps_set_intr(do_pf_read_start, NULL, 0, nice); 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic void do_pf_read_start(void) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci pf_busy = 1; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (pf_start(pf_current, ATAPI_READ_10, pf_block, pf_run)) { 9298c2ecf20Sopenharmony_ci pi_disconnect(pf_current->pi); 9308c2ecf20Sopenharmony_ci if (pf_retries < PF_MAX_RETRIES) { 9318c2ecf20Sopenharmony_ci pf_retries++; 9328c2ecf20Sopenharmony_ci pi_do_claimed(pf_current->pi, do_pf_read_start); 9338c2ecf20Sopenharmony_ci return; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci next_request(BLK_STS_IOERR); 9368c2ecf20Sopenharmony_ci return; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci pf_mask = STAT_DRQ; 9398c2ecf20Sopenharmony_ci ps_set_intr(do_pf_read_drq, pf_ready, PF_TMO, nice); 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic void do_pf_read_drq(void) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci while (1) { 9458c2ecf20Sopenharmony_ci if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, 9468c2ecf20Sopenharmony_ci "read block", "completion") & STAT_ERR) { 9478c2ecf20Sopenharmony_ci pi_disconnect(pf_current->pi); 9488c2ecf20Sopenharmony_ci if (pf_retries < PF_MAX_RETRIES) { 9498c2ecf20Sopenharmony_ci pf_req_sense(pf_current, 0); 9508c2ecf20Sopenharmony_ci pf_retries++; 9518c2ecf20Sopenharmony_ci pi_do_claimed(pf_current->pi, do_pf_read_start); 9528c2ecf20Sopenharmony_ci return; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci next_request(BLK_STS_IOERR); 9558c2ecf20Sopenharmony_ci return; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci pi_read_block(pf_current->pi, pf_buf, 512); 9588c2ecf20Sopenharmony_ci if (pf_next_buf()) 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci pi_disconnect(pf_current->pi); 9628c2ecf20Sopenharmony_ci next_request(0); 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic void do_pf_write(void) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci ps_set_intr(do_pf_write_start, NULL, 0, nice); 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic void do_pf_write_start(void) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci pf_busy = 1; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (pf_start(pf_current, ATAPI_WRITE_10, pf_block, pf_run)) { 9758c2ecf20Sopenharmony_ci pi_disconnect(pf_current->pi); 9768c2ecf20Sopenharmony_ci if (pf_retries < PF_MAX_RETRIES) { 9778c2ecf20Sopenharmony_ci pf_retries++; 9788c2ecf20Sopenharmony_ci pi_do_claimed(pf_current->pi, do_pf_write_start); 9798c2ecf20Sopenharmony_ci return; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci next_request(BLK_STS_IOERR); 9828c2ecf20Sopenharmony_ci return; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci while (1) { 9868c2ecf20Sopenharmony_ci if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, 9878c2ecf20Sopenharmony_ci "write block", "data wait") & STAT_ERR) { 9888c2ecf20Sopenharmony_ci pi_disconnect(pf_current->pi); 9898c2ecf20Sopenharmony_ci if (pf_retries < PF_MAX_RETRIES) { 9908c2ecf20Sopenharmony_ci pf_retries++; 9918c2ecf20Sopenharmony_ci pi_do_claimed(pf_current->pi, do_pf_write_start); 9928c2ecf20Sopenharmony_ci return; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci next_request(BLK_STS_IOERR); 9958c2ecf20Sopenharmony_ci return; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci pi_write_block(pf_current->pi, pf_buf, 512); 9988c2ecf20Sopenharmony_ci if (pf_next_buf()) 9998c2ecf20Sopenharmony_ci break; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci pf_mask = 0; 10028c2ecf20Sopenharmony_ci ps_set_intr(do_pf_write_done, pf_ready, PF_TMO, nice); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic void do_pf_write_done(void) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci if (pf_wait(pf_current, STAT_BUSY, 0, "write block", "done") & STAT_ERR) { 10088c2ecf20Sopenharmony_ci pi_disconnect(pf_current->pi); 10098c2ecf20Sopenharmony_ci if (pf_retries < PF_MAX_RETRIES) { 10108c2ecf20Sopenharmony_ci pf_retries++; 10118c2ecf20Sopenharmony_ci pi_do_claimed(pf_current->pi, do_pf_write_start); 10128c2ecf20Sopenharmony_ci return; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci next_request(BLK_STS_IOERR); 10158c2ecf20Sopenharmony_ci return; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci pi_disconnect(pf_current->pi); 10188c2ecf20Sopenharmony_ci next_request(0); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic int __init pf_init(void) 10228c2ecf20Sopenharmony_ci{ /* preliminary initialisation */ 10238c2ecf20Sopenharmony_ci struct pf_unit *pf; 10248c2ecf20Sopenharmony_ci int unit; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (disable) 10278c2ecf20Sopenharmony_ci return -EINVAL; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci pf_init_units(); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (pf_detect()) 10328c2ecf20Sopenharmony_ci return -ENODEV; 10338c2ecf20Sopenharmony_ci pf_busy = 0; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (register_blkdev(major, name)) { 10368c2ecf20Sopenharmony_ci for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { 10378c2ecf20Sopenharmony_ci if (!pf->disk) 10388c2ecf20Sopenharmony_ci continue; 10398c2ecf20Sopenharmony_ci blk_cleanup_queue(pf->disk->queue); 10408c2ecf20Sopenharmony_ci blk_mq_free_tag_set(&pf->tag_set); 10418c2ecf20Sopenharmony_ci put_disk(pf->disk); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci return -EBUSY; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { 10478c2ecf20Sopenharmony_ci struct gendisk *disk = pf->disk; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (!pf->present) 10508c2ecf20Sopenharmony_ci continue; 10518c2ecf20Sopenharmony_ci disk->private_data = pf; 10528c2ecf20Sopenharmony_ci add_disk(disk); 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic void __exit pf_exit(void) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci struct pf_unit *pf; 10608c2ecf20Sopenharmony_ci int unit; 10618c2ecf20Sopenharmony_ci unregister_blkdev(major, name); 10628c2ecf20Sopenharmony_ci for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { 10638c2ecf20Sopenharmony_ci if (!pf->disk) 10648c2ecf20Sopenharmony_ci continue; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (pf->present) 10678c2ecf20Sopenharmony_ci del_gendisk(pf->disk); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci blk_cleanup_queue(pf->disk->queue); 10708c2ecf20Sopenharmony_ci blk_mq_free_tag_set(&pf->tag_set); 10718c2ecf20Sopenharmony_ci put_disk(pf->disk); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (pf->present) 10748c2ecf20Sopenharmony_ci pi_release(pf->pi); 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 10798c2ecf20Sopenharmony_cimodule_init(pf_init) 10808c2ecf20Sopenharmony_cimodule_exit(pf_exit) 1081