1507c3241Smlf /*
2507c3241Smlf * CDDL HEADER START
3507c3241Smlf *
4507c3241Smlf * The contents of this file are subject to the terms of the
5e8fb11a1Sshidokht * Common Development and Distribution License (the "License").
6e8fb11a1Sshidokht * You may not use this file except in compliance with the License.
7507c3241Smlf *
8507c3241Smlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9507c3241Smlf * or http://www.opensolaris.org/os/licensing.
10507c3241Smlf * See the License for the specific language governing permissions
11507c3241Smlf * and limitations under the License.
12507c3241Smlf *
13507c3241Smlf * When distributing Covered Code, include this CDDL HEADER in each
14507c3241Smlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15507c3241Smlf * If applicable, add the following below this CDDL HEADER, with the
16507c3241Smlf * fields enclosed by brackets "[]" replaced with your own identifying
17507c3241Smlf * information: Portions Copyright [yyyy] [name of copyright owner]
18507c3241Smlf *
19507c3241Smlf * CDDL HEADER END
20507c3241Smlf */
21342440ecSPrasad Singamsetty
22507c3241Smlf /*
238b6b46faSzhongyan gu - Sun Microsystems - Beijing China * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24507c3241Smlf */
25507c3241Smlf
26507c3241Smlf #include <sys/scsi/scsi.h>
27507c3241Smlf #include <sys/dktp/cm.h>
28507c3241Smlf #include <sys/dktp/quetypes.h>
29507c3241Smlf #include <sys/dktp/queue.h>
30507c3241Smlf #include <sys/dktp/fctypes.h>
31507c3241Smlf #include <sys/dktp/flowctrl.h>
32507c3241Smlf #include <sys/dktp/cmdev.h>
33507c3241Smlf #include <sys/dkio.h>
34507c3241Smlf #include <sys/dktp/tgdk.h>
35507c3241Smlf #include <sys/dktp/dadk.h>
36507c3241Smlf #include <sys/dktp/bbh.h>
37507c3241Smlf #include <sys/dktp/altsctr.h>
38507c3241Smlf #include <sys/dktp/cmdk.h>
39507c3241Smlf
40507c3241Smlf #include <sys/stat.h>
41507c3241Smlf #include <sys/vtoc.h>
42507c3241Smlf #include <sys/file.h>
43507c3241Smlf #include <sys/dktp/dadkio.h>
44507c3241Smlf #include <sys/aio_req.h>
45507c3241Smlf
46507c3241Smlf #include <sys/cmlb.h>
47507c3241Smlf
48507c3241Smlf /*
49507c3241Smlf * Local Static Data
50507c3241Smlf */
51507c3241Smlf #ifdef CMDK_DEBUG
52507c3241Smlf #define DENT 0x0001
53507c3241Smlf #define DIO 0x0002
54507c3241Smlf
55507c3241Smlf static int cmdk_debug = DIO;
56507c3241Smlf #endif
57507c3241Smlf
58507c3241Smlf #ifndef TRUE
59507c3241Smlf #define TRUE 1
60507c3241Smlf #endif
61507c3241Smlf
62507c3241Smlf #ifndef FALSE
63507c3241Smlf #define FALSE 0
64507c3241Smlf #endif
65507c3241Smlf
66507c3241Smlf /*
67507c3241Smlf * NDKMAP is the base number for accessing the fdisk partitions.
68507c3241Smlf * c?d?p0 --> cmdk@?,?:q
69507c3241Smlf */
70507c3241Smlf #define PARTITION0_INDEX (NDKMAP + 0)
71507c3241Smlf
72507c3241Smlf #define DKTP_DATA (dkp->dk_tgobjp)->tg_data
73507c3241Smlf #define DKTP_EXT (dkp->dk_tgobjp)->tg_ext
74507c3241Smlf
757f0b8309SEdward Pilatowicz void *cmdk_state;
76507c3241Smlf
77507c3241Smlf /*
78507c3241Smlf * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded
79507c3241Smlf * attach situations
80507c3241Smlf */
81507c3241Smlf static kmutex_t cmdk_attach_mutex;
82507c3241Smlf static int cmdk_max_instance = 0;
83507c3241Smlf
84507c3241Smlf /*
85507c3241Smlf * Panic dumpsys state
86507c3241Smlf * There is only a single flag that is not mutex locked since
87507c3241Smlf * the system is prevented from thread switching and cmdk_dump
88507c3241Smlf * will only be called in a single threaded operation.
89507c3241Smlf */
90507c3241Smlf static int cmdk_indump;
91507c3241Smlf
92507c3241Smlf /*
93507c3241Smlf * Local Function Prototypes
94507c3241Smlf */
95507c3241Smlf static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp);
96507c3241Smlf static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp);
97507c3241Smlf static void cmdkmin(struct buf *bp);
98507c3241Smlf static int cmdkrw(dev_t dev, struct uio *uio, int flag);
99507c3241Smlf static int cmdkarw(dev_t dev, struct aio_req *aio, int flag);
100507c3241Smlf
101507c3241Smlf /*
102507c3241Smlf * Bad Block Handling Functions Prototypes
103507c3241Smlf */
104507c3241Smlf static void cmdk_bbh_reopen(struct cmdk *dkp);
105507c3241Smlf static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp);
106507c3241Smlf static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle);
107507c3241Smlf static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle);
108507c3241Smlf static void cmdk_bbh_close(struct cmdk *dkp);
109507c3241Smlf static void cmdk_bbh_setalts_idx(struct cmdk *dkp);
110507c3241Smlf static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key);
111507c3241Smlf
112507c3241Smlf static struct bbh_objops cmdk_bbh_ops = {
113507c3241Smlf nulldev,
114507c3241Smlf nulldev,
115507c3241Smlf cmdk_bbh_gethandle,
116507c3241Smlf cmdk_bbh_htoc,
117507c3241Smlf cmdk_bbh_freehandle,
118507c3241Smlf 0, 0
119507c3241Smlf };
120507c3241Smlf
121507c3241Smlf static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp);
122507c3241Smlf static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp);
123507c3241Smlf static int cmdkstrategy(struct buf *bp);
124507c3241Smlf static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
125507c3241Smlf static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *);
126507c3241Smlf static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp);
127507c3241Smlf static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp);
128507c3241Smlf static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
129507c3241Smlf int mod_flags, char *name, caddr_t valuep, int *lengthp);
130507c3241Smlf static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp);
131507c3241Smlf static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp);
132507c3241Smlf
133507c3241Smlf /*
134507c3241Smlf * Device driver ops vector
135507c3241Smlf */
136507c3241Smlf
137507c3241Smlf static struct cb_ops cmdk_cb_ops = {
138507c3241Smlf cmdkopen, /* open */
139507c3241Smlf cmdkclose, /* close */
140507c3241Smlf cmdkstrategy, /* strategy */
141507c3241Smlf nodev, /* print */
142507c3241Smlf cmdkdump, /* dump */
143507c3241Smlf cmdkread, /* read */
144507c3241Smlf cmdkwrite, /* write */
145507c3241Smlf cmdkioctl, /* ioctl */
146507c3241Smlf nodev, /* devmap */
147507c3241Smlf nodev, /* mmap */
148507c3241Smlf nodev, /* segmap */
149507c3241Smlf nochpoll, /* poll */
150507c3241Smlf cmdk_prop_op, /* cb_prop_op */
151507c3241Smlf 0, /* streamtab */
152507c3241Smlf D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */
153507c3241Smlf CB_REV, /* cb_rev */
154507c3241Smlf cmdkaread, /* async read */
155507c3241Smlf cmdkawrite /* async write */
156507c3241Smlf };
157507c3241Smlf
158507c3241Smlf static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
159507c3241Smlf void **result);
160507c3241Smlf static int cmdkprobe(dev_info_t *dip);
161507c3241Smlf static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
162507c3241Smlf static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
163507c3241Smlf
1642df1fe9cSrandyf static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp);
1652df1fe9cSrandyf static int cmdkresume(dev_info_t *dip);
1662df1fe9cSrandyf static int cmdksuspend(dev_info_t *dip);
1672df1fe9cSrandyf static int cmdkpower(dev_info_t *dip, int component, int level);
1682df1fe9cSrandyf
169507c3241Smlf struct dev_ops cmdk_ops = {
170507c3241Smlf DEVO_REV, /* devo_rev, */
171507c3241Smlf 0, /* refcnt */
172507c3241Smlf cmdkinfo, /* info */
173507c3241Smlf nulldev, /* identify */
174507c3241Smlf cmdkprobe, /* probe */
175507c3241Smlf cmdkattach, /* attach */
176507c3241Smlf cmdkdetach, /* detach */
177507c3241Smlf nodev, /* reset */
178507c3241Smlf &cmdk_cb_ops, /* driver operations */
1792df1fe9cSrandyf (struct bus_ops *)0, /* bus operations */
18019397407SSherry Moore cmdkpower, /* power */
18119397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */
182507c3241Smlf };
183507c3241Smlf
184507c3241Smlf /*
185507c3241Smlf * This is the loadable module wrapper.
186507c3241Smlf */
187507c3241Smlf #include <sys/modctl.h>
188507c3241Smlf
1897f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
190507c3241Smlf static struct modldrv modldrv = {
191507c3241Smlf &mod_driverops, /* Type of module. This one is a driver */
192613b2871SRichard Bean "Common Direct Access Disk",
193507c3241Smlf &cmdk_ops, /* driver ops */
194507c3241Smlf };
195507c3241Smlf
196507c3241Smlf static struct modlinkage modlinkage = {
197507c3241Smlf MODREV_1, (void *)&modldrv, NULL
198507c3241Smlf };
199507c3241Smlf
2007f0b8309SEdward Pilatowicz
2017f0b8309SEdward Pilatowicz #else /* XPV_HVM_DRIVER */
2027f0b8309SEdward Pilatowicz static struct modlmisc modlmisc = {
2037f0b8309SEdward Pilatowicz &mod_miscops, /* Type of module. This one is a misc */
2047f0b8309SEdward Pilatowicz "HVM Common Direct Access Disk",
2057f0b8309SEdward Pilatowicz };
2067f0b8309SEdward Pilatowicz
2077f0b8309SEdward Pilatowicz static struct modlinkage modlinkage = {
2087f0b8309SEdward Pilatowicz MODREV_1, (void *)&modlmisc, NULL
2097f0b8309SEdward Pilatowicz };
2107f0b8309SEdward Pilatowicz
2117f0b8309SEdward Pilatowicz #endif /* XPV_HVM_DRIVER */
2127f0b8309SEdward Pilatowicz
213507c3241Smlf /* Function prototypes for cmlb callbacks */
214507c3241Smlf
215507c3241Smlf static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
216e8fb11a1Sshidokht diskaddr_t start, size_t length, void *tg_cookie);
217e8fb11a1Sshidokht
218e8fb11a1Sshidokht static int cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg,
219e8fb11a1Sshidokht void *tg_cookie);
220507c3241Smlf
221507c3241Smlf static void cmdk_devid_setup(struct cmdk *dkp);
222507c3241Smlf static int cmdk_devid_modser(struct cmdk *dkp);
223507c3241Smlf static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len);
224507c3241Smlf static int cmdk_devid_fabricate(struct cmdk *dkp);
225507c3241Smlf static int cmdk_devid_read(struct cmdk *dkp);
226507c3241Smlf
227507c3241Smlf static cmlb_tg_ops_t cmdk_lb_ops = {
228e8fb11a1Sshidokht TG_DK_OPS_VERSION_1,
229507c3241Smlf cmdk_lb_rdwr,
230e8fb11a1Sshidokht cmdk_lb_getinfo
231507c3241Smlf };
232507c3241Smlf
23306bbe1e0Sedp static boolean_t
cmdk_isopen(struct cmdk * dkp,dev_t dev)23406bbe1e0Sedp cmdk_isopen(struct cmdk *dkp, dev_t dev)
23506bbe1e0Sedp {
23606bbe1e0Sedp int part, otyp;
23706bbe1e0Sedp ulong_t partbit;
23806bbe1e0Sedp
23906bbe1e0Sedp ASSERT(MUTEX_HELD((&dkp->dk_mutex)));
24006bbe1e0Sedp
24106bbe1e0Sedp part = CMDKPART(dev);
24206bbe1e0Sedp partbit = 1 << part;
24306bbe1e0Sedp
24406bbe1e0Sedp /* account for close */
24506bbe1e0Sedp if (dkp->dk_open_lyr[part] != 0)
24606bbe1e0Sedp return (B_TRUE);
24706bbe1e0Sedp for (otyp = 0; otyp < OTYPCNT; otyp++)
24806bbe1e0Sedp if (dkp->dk_open_reg[otyp] & partbit)
24906bbe1e0Sedp return (B_TRUE);
25006bbe1e0Sedp return (B_FALSE);
25106bbe1e0Sedp }
25206bbe1e0Sedp
253507c3241Smlf int
_init(void)254507c3241Smlf _init(void)
255507c3241Smlf {
256507c3241Smlf int rval;
257507c3241Smlf
2587f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
259507c3241Smlf if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7))
260507c3241Smlf return (rval);
2617f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
262507c3241Smlf
263507c3241Smlf mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL);
264507c3241Smlf if ((rval = mod_install(&modlinkage)) != 0) {
265507c3241Smlf mutex_destroy(&cmdk_attach_mutex);
2667f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
267507c3241Smlf ddi_soft_state_fini(&cmdk_state);
2687f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
269507c3241Smlf }
270507c3241Smlf return (rval);
271507c3241Smlf }
272507c3241Smlf
273507c3241Smlf int
_fini(void)274507c3241Smlf _fini(void)
275507c3241Smlf {
276507c3241Smlf return (EBUSY);
277507c3241Smlf }
278507c3241Smlf
279507c3241Smlf int
_info(struct modinfo * modinfop)280507c3241Smlf _info(struct modinfo *modinfop)
281507c3241Smlf {
282507c3241Smlf return (mod_info(&modlinkage, modinfop));
283507c3241Smlf }
284507c3241Smlf
285507c3241Smlf /*
286507c3241Smlf * Autoconfiguration Routines
287507c3241Smlf */
288507c3241Smlf static int
cmdkprobe(dev_info_t * dip)289507c3241Smlf cmdkprobe(dev_info_t *dip)
290507c3241Smlf {
291507c3241Smlf int instance;
292507c3241Smlf int status;
293507c3241Smlf struct cmdk *dkp;
294507c3241Smlf
295507c3241Smlf instance = ddi_get_instance(dip);
296507c3241Smlf
2977f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
298507c3241Smlf if (ddi_get_soft_state(cmdk_state, instance))
299507c3241Smlf return (DDI_PROBE_PARTIAL);
300507c3241Smlf
3017f0b8309SEdward Pilatowicz if (ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS)
3027f0b8309SEdward Pilatowicz return (DDI_PROBE_PARTIAL);
3037f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
3047f0b8309SEdward Pilatowicz
3057f0b8309SEdward Pilatowicz if ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL)
306507c3241Smlf return (DDI_PROBE_PARTIAL);
307507c3241Smlf
308507c3241Smlf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
309507c3241Smlf rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL);
310507c3241Smlf dkp->dk_dip = dip;
311507c3241Smlf mutex_enter(&dkp->dk_mutex);
312507c3241Smlf
313507c3241Smlf dkp->dk_dev = makedevice(ddi_driver_major(dip),
314507c3241Smlf ddi_get_instance(dip) << CMDK_UNITSHF);
315507c3241Smlf
316507c3241Smlf /* linkage to dadk and strategy */
317507c3241Smlf if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) {
318507c3241Smlf mutex_exit(&dkp->dk_mutex);
319507c3241Smlf mutex_destroy(&dkp->dk_mutex);
320507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex);
3217f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
322507c3241Smlf ddi_soft_state_free(cmdk_state, instance);
3237f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
324507c3241Smlf return (DDI_PROBE_PARTIAL);
325507c3241Smlf }
326507c3241Smlf
327507c3241Smlf status = dadk_probe(DKTP_DATA, KM_NOSLEEP);
328507c3241Smlf if (status != DDI_PROBE_SUCCESS) {
329507c3241Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */
330507c3241Smlf mutex_exit(&dkp->dk_mutex);
331507c3241Smlf mutex_destroy(&dkp->dk_mutex);
332507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex);
3337f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
334507c3241Smlf ddi_soft_state_free(cmdk_state, instance);
3357f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
336507c3241Smlf return (status);
337507c3241Smlf }
338507c3241Smlf
339507c3241Smlf mutex_exit(&dkp->dk_mutex);
340507c3241Smlf #ifdef CMDK_DEBUG
341507c3241Smlf if (cmdk_debug & DENT)
342507c3241Smlf PRF("cmdkprobe: instance= %d name= `%s`\n",
343507c3241Smlf instance, ddi_get_name_addr(dip));
344507c3241Smlf #endif
345507c3241Smlf return (status);
346507c3241Smlf }
347507c3241Smlf
348507c3241Smlf static int
cmdkattach(dev_info_t * dip,ddi_attach_cmd_t cmd)349507c3241Smlf cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
350507c3241Smlf {
351507c3241Smlf int instance;
352507c3241Smlf struct cmdk *dkp;
353507c3241Smlf char *node_type;
354507c3241Smlf
3552df1fe9cSrandyf switch (cmd) {
3562df1fe9cSrandyf case DDI_ATTACH:
3572df1fe9cSrandyf break;
3582df1fe9cSrandyf case DDI_RESUME:
3592df1fe9cSrandyf return (cmdkresume(dip));
3602df1fe9cSrandyf default:
361507c3241Smlf return (DDI_FAILURE);
3622df1fe9cSrandyf }
363507c3241Smlf
364507c3241Smlf instance = ddi_get_instance(dip);
365507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
366507c3241Smlf return (DDI_FAILURE);
367507c3241Smlf
3682df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
3692df1fe9cSrandyf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL);
3702df1fe9cSrandyf
371507c3241Smlf mutex_enter(&dkp->dk_mutex);
372507c3241Smlf
373507c3241Smlf /* dadk_attach is an empty function that only returns SUCCESS */
374507c3241Smlf (void) dadk_attach(DKTP_DATA);
375507c3241Smlf
376507c3241Smlf node_type = (DKTP_EXT->tg_nodetype);
377507c3241Smlf
378507c3241Smlf /*
379507c3241Smlf * this open allows cmlb to read the device
380507c3241Smlf * and determine the label types
381507c3241Smlf * so that cmlb can create minor nodes for device
382507c3241Smlf */
383507c3241Smlf
384507c3241Smlf /* open the target disk */
385507c3241Smlf if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS)
386507c3241Smlf goto fail2;
387507c3241Smlf
388342440ecSPrasad Singamsetty #ifdef _ILP32
389342440ecSPrasad Singamsetty {
390342440ecSPrasad Singamsetty struct tgdk_geom phyg;
391342440ecSPrasad Singamsetty (void) dadk_getphygeom(DKTP_DATA, &phyg);
392342440ecSPrasad Singamsetty if ((phyg.g_cap - 1) > DK_MAX_BLOCKS) {
393342440ecSPrasad Singamsetty (void) dadk_close(DKTP_DATA);
394342440ecSPrasad Singamsetty goto fail2;
395342440ecSPrasad Singamsetty }
396342440ecSPrasad Singamsetty }
397342440ecSPrasad Singamsetty #endif
398342440ecSPrasad Singamsetty
399342440ecSPrasad Singamsetty
400507c3241Smlf /* mark as having opened target */
401507c3241Smlf dkp->dk_flag |= CMDK_TGDK_OPEN;
402507c3241Smlf
403507c3241Smlf cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle);
404507c3241Smlf
405507c3241Smlf if (cmlb_attach(dip,
406507c3241Smlf &cmdk_lb_ops,
407507c3241Smlf DTYPE_DIRECT, /* device_type */
4087f0b8309SEdward Pilatowicz B_FALSE, /* removable */
4097f0b8309SEdward Pilatowicz B_FALSE, /* hot pluggable XXX */
410507c3241Smlf node_type,
411507c3241Smlf CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* alter_behaviour */
412e8fb11a1Sshidokht dkp->dk_cmlbhandle,
413e8fb11a1Sshidokht 0) != 0)
414507c3241Smlf goto fail1;
415507c3241Smlf
416507c3241Smlf /* Calling validate will create minor nodes according to disk label */
417e8fb11a1Sshidokht (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0);
418507c3241Smlf
419507c3241Smlf /* set bbh (Bad Block Handling) */
420507c3241Smlf cmdk_bbh_reopen(dkp);
421507c3241Smlf
422507c3241Smlf /* setup devid string */
423507c3241Smlf cmdk_devid_setup(dkp);
424507c3241Smlf
425507c3241Smlf mutex_enter(&cmdk_attach_mutex);
426507c3241Smlf if (instance > cmdk_max_instance)
427507c3241Smlf cmdk_max_instance = instance;
428507c3241Smlf mutex_exit(&cmdk_attach_mutex);
429507c3241Smlf
430507c3241Smlf mutex_exit(&dkp->dk_mutex);
431507c3241Smlf
432507c3241Smlf /*
433507c3241Smlf * Add a zero-length attribute to tell the world we support
434507c3241Smlf * kernel ioctls (for layered drivers)
435507c3241Smlf */
436507c3241Smlf (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
437507c3241Smlf DDI_KERNEL_IOCTL, NULL, 0);
438507c3241Smlf ddi_report_dev(dip);
439507c3241Smlf
4402df1fe9cSrandyf /*
4412df1fe9cSrandyf * Initialize power management
4422df1fe9cSrandyf */
4432df1fe9cSrandyf mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL);
4442df1fe9cSrandyf cv_init(&dkp->dk_suspend_cv, NULL, CV_DRIVER, NULL);
4452df1fe9cSrandyf cmdk_setup_pm(dip, dkp);
4462df1fe9cSrandyf
447507c3241Smlf return (DDI_SUCCESS);
448507c3241Smlf
449507c3241Smlf fail1:
450507c3241Smlf cmlb_free_handle(&dkp->dk_cmlbhandle);
451507c3241Smlf (void) dadk_close(DKTP_DATA);
452507c3241Smlf fail2:
453507c3241Smlf cmdk_destroy_obj(dip, dkp);
454507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex);
455507c3241Smlf mutex_exit(&dkp->dk_mutex);
456507c3241Smlf mutex_destroy(&dkp->dk_mutex);
4577f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
458507c3241Smlf ddi_soft_state_free(cmdk_state, instance);
4597f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
460507c3241Smlf return (DDI_FAILURE);
461507c3241Smlf }
462507c3241Smlf
463507c3241Smlf
464507c3241Smlf static int
cmdkdetach(dev_info_t * dip,ddi_detach_cmd_t cmd)465507c3241Smlf cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
466507c3241Smlf {
467507c3241Smlf struct cmdk *dkp;
468507c3241Smlf int instance;
469507c3241Smlf int max_instance;
470507c3241Smlf
4712df1fe9cSrandyf switch (cmd) {
4722df1fe9cSrandyf case DDI_DETACH:
4732df1fe9cSrandyf /* return (DDI_FAILURE); */
4742df1fe9cSrandyf break;
4752df1fe9cSrandyf case DDI_SUSPEND:
4762df1fe9cSrandyf return (cmdksuspend(dip));
4772df1fe9cSrandyf default:
478507c3241Smlf #ifdef CMDK_DEBUG
479507c3241Smlf if (cmdk_debug & DIO) {
480507c3241Smlf PRF("cmdkdetach: cmd = %d unknown\n", cmd);
481507c3241Smlf }
482507c3241Smlf #endif
483507c3241Smlf return (DDI_FAILURE);
484507c3241Smlf }
485507c3241Smlf
486507c3241Smlf mutex_enter(&cmdk_attach_mutex);
487507c3241Smlf max_instance = cmdk_max_instance;
488507c3241Smlf mutex_exit(&cmdk_attach_mutex);
489507c3241Smlf
490507c3241Smlf /* check if any instance of driver is open */
491507c3241Smlf for (instance = 0; instance < max_instance; instance++) {
492507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, instance);
493507c3241Smlf if (!dkp)
494507c3241Smlf continue;
495507c3241Smlf if (dkp->dk_flag & CMDK_OPEN)
496507c3241Smlf return (DDI_FAILURE);
497507c3241Smlf }
498507c3241Smlf
499507c3241Smlf instance = ddi_get_instance(dip);
500507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
501507c3241Smlf return (DDI_SUCCESS);
502507c3241Smlf
503507c3241Smlf mutex_enter(&dkp->dk_mutex);
504507c3241Smlf
505507c3241Smlf /*
506507c3241Smlf * The cmdk_part_info call at the end of cmdkattach may have
507507c3241Smlf * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on
508507c3241Smlf * detach for case when cmdkopen/cmdkclose never occurs.
509507c3241Smlf */
510507c3241Smlf if (dkp->dk_flag & CMDK_TGDK_OPEN) {
511507c3241Smlf dkp->dk_flag &= ~CMDK_TGDK_OPEN;
512507c3241Smlf (void) dadk_close(DKTP_DATA);
513507c3241Smlf }
514507c3241Smlf
515e8fb11a1Sshidokht cmlb_detach(dkp->dk_cmlbhandle, 0);
516507c3241Smlf cmlb_free_handle(&dkp->dk_cmlbhandle);
517507c3241Smlf ddi_prop_remove_all(dip);
518507c3241Smlf
519507c3241Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */
5208b6b46faSzhongyan gu - Sun Microsystems - Beijing China
5218b6b46faSzhongyan gu - Sun Microsystems - Beijing China /*
5228b6b46faSzhongyan gu - Sun Microsystems - Beijing China * free the devid structure if allocated before
5238b6b46faSzhongyan gu - Sun Microsystems - Beijing China */
5248b6b46faSzhongyan gu - Sun Microsystems - Beijing China if (dkp->dk_devid) {
5258b6b46faSzhongyan gu - Sun Microsystems - Beijing China ddi_devid_free(dkp->dk_devid);
5268b6b46faSzhongyan gu - Sun Microsystems - Beijing China dkp->dk_devid = NULL;
5278b6b46faSzhongyan gu - Sun Microsystems - Beijing China }
5288b6b46faSzhongyan gu - Sun Microsystems - Beijing China
529507c3241Smlf mutex_exit(&dkp->dk_mutex);
530507c3241Smlf mutex_destroy(&dkp->dk_mutex);
531507c3241Smlf rw_destroy(&dkp->dk_bbh_mutex);
5322df1fe9cSrandyf mutex_destroy(&dkp->dk_pm_mutex);
5332df1fe9cSrandyf cv_destroy(&dkp->dk_suspend_cv);
5347f0b8309SEdward Pilatowicz #ifndef XPV_HVM_DRIVER
535507c3241Smlf ddi_soft_state_free(cmdk_state, instance);
5367f0b8309SEdward Pilatowicz #endif /* !XPV_HVM_DRIVER */
537507c3241Smlf
538507c3241Smlf return (DDI_SUCCESS);
539507c3241Smlf }
540507c3241Smlf
541507c3241Smlf static int
cmdkinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)542507c3241Smlf cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
543507c3241Smlf {
544507c3241Smlf dev_t dev = (dev_t)arg;
545507c3241Smlf int instance;
546507c3241Smlf struct cmdk *dkp;
547507c3241Smlf
548507c3241Smlf #ifdef lint
549507c3241Smlf dip = dip; /* no one ever uses this */
550507c3241Smlf #endif
551507c3241Smlf #ifdef CMDK_DEBUG
552507c3241Smlf if (cmdk_debug & DENT)
553507c3241Smlf PRF("cmdkinfo: call\n");
554507c3241Smlf #endif
555507c3241Smlf instance = CMDKUNIT(dev);
556507c3241Smlf
557507c3241Smlf switch (infocmd) {
558507c3241Smlf case DDI_INFO_DEVT2DEVINFO:
559507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
560507c3241Smlf return (DDI_FAILURE);
561507c3241Smlf *result = (void *) dkp->dk_dip;
562507c3241Smlf break;
563507c3241Smlf case DDI_INFO_DEVT2INSTANCE:
564507c3241Smlf *result = (void *)(intptr_t)instance;
565507c3241Smlf break;
566507c3241Smlf default:
567507c3241Smlf return (DDI_FAILURE);
568507c3241Smlf }
569507c3241Smlf return (DDI_SUCCESS);
570507c3241Smlf }
571507c3241Smlf
5722df1fe9cSrandyf /*
5732df1fe9cSrandyf * Initialize the power management components
5742df1fe9cSrandyf */
5752df1fe9cSrandyf static void
cmdk_setup_pm(dev_info_t * dip,struct cmdk * dkp)5762df1fe9cSrandyf cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp)
5772df1fe9cSrandyf {
5782df1fe9cSrandyf char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL };
5792df1fe9cSrandyf
5802df1fe9cSrandyf /*
5812df1fe9cSrandyf * Since the cmdk device does not the 'reg' property,
5822df1fe9cSrandyf * cpr will not call its DDI_SUSPEND/DDI_RESUME entries.
5832df1fe9cSrandyf * The following code is to tell cpr that this device
5842df1fe9cSrandyf * DOES need to be suspended and resumed.
5852df1fe9cSrandyf */
5862df1fe9cSrandyf (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
5872df1fe9cSrandyf "pm-hardware-state", "needs-suspend-resume");
5882df1fe9cSrandyf
5892df1fe9cSrandyf if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
5902df1fe9cSrandyf "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) {
5912df1fe9cSrandyf if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) {
5922df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex);
5932df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_ON;
5942df1fe9cSrandyf dkp->dk_pm_is_enabled = 1;
5952df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex);
5962df1fe9cSrandyf } else {
5972df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex);
5982df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_OFF;
5992df1fe9cSrandyf dkp->dk_pm_is_enabled = 0;
6002df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex);
6012df1fe9cSrandyf }
6022df1fe9cSrandyf } else {
6032df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex);
6042df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT;
6052df1fe9cSrandyf dkp->dk_pm_is_enabled = 0;
6062df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex);
6072df1fe9cSrandyf }
6082df1fe9cSrandyf }
6092df1fe9cSrandyf
6102df1fe9cSrandyf /*
6112df1fe9cSrandyf * suspend routine, it will be run when get the command
6122df1fe9cSrandyf * DDI_SUSPEND at detach(9E) from system power management
6132df1fe9cSrandyf */
6142df1fe9cSrandyf static int
cmdksuspend(dev_info_t * dip)6152df1fe9cSrandyf cmdksuspend(dev_info_t *dip)
6162df1fe9cSrandyf {
6172df1fe9cSrandyf struct cmdk *dkp;
6182df1fe9cSrandyf int instance;
6192df1fe9cSrandyf clock_t count = 0;
6202df1fe9cSrandyf
6212df1fe9cSrandyf instance = ddi_get_instance(dip);
6222df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
6232df1fe9cSrandyf return (DDI_FAILURE);
6242df1fe9cSrandyf mutex_enter(&dkp->dk_mutex);
6252df1fe9cSrandyf if (dkp->dk_flag & CMDK_SUSPEND) {
6262df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
6272df1fe9cSrandyf return (DDI_SUCCESS);
6282df1fe9cSrandyf }
6292df1fe9cSrandyf dkp->dk_flag |= CMDK_SUSPEND;
6302df1fe9cSrandyf
6312df1fe9cSrandyf /* need to wait a while */
6322df1fe9cSrandyf while (dadk_getcmds(DKTP_DATA) != 0) {
6332df1fe9cSrandyf delay(drv_usectohz(1000000));
6342df1fe9cSrandyf if (count > 60) {
6352df1fe9cSrandyf dkp->dk_flag &= ~CMDK_SUSPEND;
6362df1fe9cSrandyf cv_broadcast(&dkp->dk_suspend_cv);
6372df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
6382df1fe9cSrandyf return (DDI_FAILURE);
6392df1fe9cSrandyf }
6402df1fe9cSrandyf count++;
6412df1fe9cSrandyf }
6422df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
6432df1fe9cSrandyf return (DDI_SUCCESS);
6442df1fe9cSrandyf }
6452df1fe9cSrandyf
6462df1fe9cSrandyf /*
6472df1fe9cSrandyf * resume routine, it will be run when get the command
6482df1fe9cSrandyf * DDI_RESUME at attach(9E) from system power management
6492df1fe9cSrandyf */
6502df1fe9cSrandyf static int
cmdkresume(dev_info_t * dip)6512df1fe9cSrandyf cmdkresume(dev_info_t *dip)
6522df1fe9cSrandyf {
6532df1fe9cSrandyf struct cmdk *dkp;
6542df1fe9cSrandyf int instance;
6552df1fe9cSrandyf
6562df1fe9cSrandyf instance = ddi_get_instance(dip);
6572df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
6582df1fe9cSrandyf return (DDI_FAILURE);
6592df1fe9cSrandyf mutex_enter(&dkp->dk_mutex);
6602df1fe9cSrandyf if (!(dkp->dk_flag & CMDK_SUSPEND)) {
6612df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
6622df1fe9cSrandyf return (DDI_FAILURE);
6632df1fe9cSrandyf }
6642df1fe9cSrandyf dkp->dk_pm_level = CMDK_SPINDLE_ON;
6652df1fe9cSrandyf dkp->dk_flag &= ~CMDK_SUSPEND;
6662df1fe9cSrandyf cv_broadcast(&dkp->dk_suspend_cv);
6672df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
6682df1fe9cSrandyf return (DDI_SUCCESS);
6692df1fe9cSrandyf
6702df1fe9cSrandyf }
6712df1fe9cSrandyf
6722df1fe9cSrandyf /*
6732df1fe9cSrandyf * power management entry point, it was used to
6742df1fe9cSrandyf * change power management component.
6752df1fe9cSrandyf * Actually, the real hard drive suspend/resume
6762df1fe9cSrandyf * was handled in ata, so this function is not
6772df1fe9cSrandyf * doing any real work other than verifying that
6782df1fe9cSrandyf * the disk is idle.
6792df1fe9cSrandyf */
6802df1fe9cSrandyf static int
cmdkpower(dev_info_t * dip,int component,int level)6812df1fe9cSrandyf cmdkpower(dev_info_t *dip, int component, int level)
6822df1fe9cSrandyf {
6832df1fe9cSrandyf struct cmdk *dkp;
6842df1fe9cSrandyf int instance;
6852df1fe9cSrandyf
6862df1fe9cSrandyf instance = ddi_get_instance(dip);
6872df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
6882df1fe9cSrandyf component != 0 || level > CMDK_SPINDLE_ON ||
6892df1fe9cSrandyf level < CMDK_SPINDLE_OFF) {
6902df1fe9cSrandyf return (DDI_FAILURE);
6912df1fe9cSrandyf }
6922df1fe9cSrandyf
6932df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex);
6942df1fe9cSrandyf if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) {
6952df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex);
6962df1fe9cSrandyf return (DDI_SUCCESS);
6972df1fe9cSrandyf }
6982df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex);
6992df1fe9cSrandyf
7002df1fe9cSrandyf if ((level == CMDK_SPINDLE_OFF) &&
7012df1fe9cSrandyf (dadk_getcmds(DKTP_DATA) != 0)) {
7022df1fe9cSrandyf return (DDI_FAILURE);
7032df1fe9cSrandyf }
7042df1fe9cSrandyf
7052df1fe9cSrandyf mutex_enter(&dkp->dk_pm_mutex);
7062df1fe9cSrandyf dkp->dk_pm_level = level;
7072df1fe9cSrandyf mutex_exit(&dkp->dk_pm_mutex);
7082df1fe9cSrandyf return (DDI_SUCCESS);
7092df1fe9cSrandyf }
7102df1fe9cSrandyf
711507c3241Smlf static int
cmdk_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)712507c3241Smlf cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
713507c3241Smlf char *name, caddr_t valuep, int *lengthp)
714507c3241Smlf {
715507c3241Smlf struct cmdk *dkp;
716507c3241Smlf
717507c3241Smlf #ifdef CMDK_DEBUG
718507c3241Smlf if (cmdk_debug & DENT)
719507c3241Smlf PRF("cmdk_prop_op: call\n");
720507c3241Smlf #endif
721507c3241Smlf
722507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
723b9ccdc5aScth if (dkp == NULL)
724b9ccdc5aScth return (ddi_prop_op(dev, dip, prop_op, mod_flags,
725507c3241Smlf name, valuep, lengthp));
726b9ccdc5aScth
727b9ccdc5aScth return (cmlb_prop_op(dkp->dk_cmlbhandle,
728b9ccdc5aScth dev, dip, prop_op, mod_flags, name, valuep, lengthp,
729b9ccdc5aScth CMDKPART(dev), NULL));
730507c3241Smlf }
731507c3241Smlf
732507c3241Smlf /*
733507c3241Smlf * dump routine
734507c3241Smlf */
735507c3241Smlf static int
cmdkdump(dev_t dev,caddr_t addr,daddr_t blkno,int nblk)736507c3241Smlf cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
737507c3241Smlf {
738507c3241Smlf int instance;
739507c3241Smlf struct cmdk *dkp;
740507c3241Smlf diskaddr_t p_lblksrt;
741507c3241Smlf diskaddr_t p_lblkcnt;
742507c3241Smlf struct buf local;
743507c3241Smlf struct buf *bp;
744507c3241Smlf
745507c3241Smlf #ifdef CMDK_DEBUG
746507c3241Smlf if (cmdk_debug & DENT)
747507c3241Smlf PRF("cmdkdump: call\n");
748507c3241Smlf #endif
749507c3241Smlf instance = CMDKUNIT(dev);
750507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0))
751507c3241Smlf return (ENXIO);
752507c3241Smlf
753507c3241Smlf if (cmlb_partinfo(
754507c3241Smlf dkp->dk_cmlbhandle,
755507c3241Smlf CMDKPART(dev),
756507c3241Smlf &p_lblkcnt,
757507c3241Smlf &p_lblksrt,
758507c3241Smlf NULL,
759e8fb11a1Sshidokht NULL,
760e8fb11a1Sshidokht 0)) {
761507c3241Smlf return (ENXIO);
762507c3241Smlf }
763507c3241Smlf
764507c3241Smlf if ((blkno+nblk) > p_lblkcnt)
765507c3241Smlf return (EINVAL);
766507c3241Smlf
767507c3241Smlf cmdk_indump = 1; /* Tell disk targets we are panic dumpping */
768507c3241Smlf
769507c3241Smlf bp = &local;
770507c3241Smlf bzero(bp, sizeof (*bp));
771507c3241Smlf bp->b_flags = B_BUSY;
772507c3241Smlf bp->b_un.b_addr = addr;
773507c3241Smlf bp->b_bcount = nblk << SCTRSHFT;
774507c3241Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno)));
775507c3241Smlf
776507c3241Smlf (void) dadk_dump(DKTP_DATA, bp);
777507c3241Smlf return (bp->b_error);
778507c3241Smlf }
779507c3241Smlf
780507c3241Smlf /*
781507c3241Smlf * Copy in the dadkio_rwcmd according to the user's data model. If needed,
782507c3241Smlf * convert it for our internal use.
783507c3241Smlf */
784507c3241Smlf static int
rwcmd_copyin(struct dadkio_rwcmd * rwcmdp,caddr_t inaddr,int flag)785507c3241Smlf rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag)
786507c3241Smlf {
787507c3241Smlf switch (ddi_model_convert_from(flag)) {
788507c3241Smlf case DDI_MODEL_ILP32: {
789507c3241Smlf struct dadkio_rwcmd32 cmd32;
790507c3241Smlf
791507c3241Smlf if (ddi_copyin(inaddr, &cmd32,
792507c3241Smlf sizeof (struct dadkio_rwcmd32), flag)) {
793507c3241Smlf return (EFAULT);
794507c3241Smlf }
795507c3241Smlf
796507c3241Smlf rwcmdp->cmd = cmd32.cmd;
797507c3241Smlf rwcmdp->flags = cmd32.flags;
798342440ecSPrasad Singamsetty rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr;
799507c3241Smlf rwcmdp->buflen = cmd32.buflen;
800507c3241Smlf rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr;
801507c3241Smlf /*
802507c3241Smlf * Note: we do not convert the 'status' field,
803507c3241Smlf * as it should not contain valid data at this
804507c3241Smlf * point.
805507c3241Smlf */
806507c3241Smlf bzero(&rwcmdp->status, sizeof (rwcmdp->status));
807507c3241Smlf break;
808507c3241Smlf }
809507c3241Smlf case DDI_MODEL_NONE: {
810507c3241Smlf if (ddi_copyin(inaddr, rwcmdp,
811507c3241Smlf sizeof (struct dadkio_rwcmd), flag)) {
812507c3241Smlf return (EFAULT);
813507c3241Smlf }
814507c3241Smlf }
815507c3241Smlf }
816507c3241Smlf return (0);
817507c3241Smlf }
818507c3241Smlf
819507c3241Smlf /*
820507c3241Smlf * If necessary, convert the internal rwcmdp and status to the appropriate
821507c3241Smlf * data model and copy it out to the user.
822507c3241Smlf */
823507c3241Smlf static int
rwcmd_copyout(struct dadkio_rwcmd * rwcmdp,caddr_t outaddr,int flag)824507c3241Smlf rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag)
825507c3241Smlf {
826507c3241Smlf switch (ddi_model_convert_from(flag)) {
827507c3241Smlf case DDI_MODEL_ILP32: {
828507c3241Smlf struct dadkio_rwcmd32 cmd32;
829507c3241Smlf
830507c3241Smlf cmd32.cmd = rwcmdp->cmd;
831507c3241Smlf cmd32.flags = rwcmdp->flags;
832507c3241Smlf cmd32.blkaddr = rwcmdp->blkaddr;
833507c3241Smlf cmd32.buflen = rwcmdp->buflen;
834507c3241Smlf ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0);
835507c3241Smlf cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr;
836507c3241Smlf
837507c3241Smlf cmd32.status.status = rwcmdp->status.status;
838507c3241Smlf cmd32.status.resid = rwcmdp->status.resid;
839507c3241Smlf cmd32.status.failed_blk_is_valid =
840507c3241Smlf rwcmdp->status.failed_blk_is_valid;
841507c3241Smlf cmd32.status.failed_blk = rwcmdp->status.failed_blk;
842507c3241Smlf cmd32.status.fru_code_is_valid =
843507c3241Smlf rwcmdp->status.fru_code_is_valid;
844507c3241Smlf cmd32.status.fru_code = rwcmdp->status.fru_code;
845507c3241Smlf
846507c3241Smlf bcopy(rwcmdp->status.add_error_info,
847507c3241Smlf cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN);
848507c3241Smlf
849507c3241Smlf if (ddi_copyout(&cmd32, outaddr,
850507c3241Smlf sizeof (struct dadkio_rwcmd32), flag))
851507c3241Smlf return (EFAULT);
852507c3241Smlf break;
853507c3241Smlf }
854507c3241Smlf case DDI_MODEL_NONE: {
855507c3241Smlf if (ddi_copyout(rwcmdp, outaddr,
856507c3241Smlf sizeof (struct dadkio_rwcmd), flag))
857507c3241Smlf return (EFAULT);
858507c3241Smlf }
859507c3241Smlf }
860507c3241Smlf return (0);
861507c3241Smlf }
862507c3241Smlf
863507c3241Smlf /*
864507c3241Smlf * ioctl routine
865507c3241Smlf */
866507c3241Smlf static int
cmdkioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * credp,int * rvalp)867507c3241Smlf cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
868507c3241Smlf {
869507c3241Smlf int instance;
870507c3241Smlf struct scsi_device *devp;
871507c3241Smlf struct cmdk *dkp;
872507c3241Smlf char data[NBPSCTR];
873507c3241Smlf
874507c3241Smlf instance = CMDKUNIT(dev);
875507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
876507c3241Smlf return (ENXIO);
877507c3241Smlf
8782df1fe9cSrandyf mutex_enter(&dkp->dk_mutex);
8792df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) {
8802df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
8812df1fe9cSrandyf }
8822df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
8832df1fe9cSrandyf
884507c3241Smlf bzero(data, sizeof (data));
885507c3241Smlf
886507c3241Smlf switch (cmd) {
887507c3241Smlf
888507c3241Smlf case DKIOCGMEDIAINFO: {
889507c3241Smlf struct dk_minfo media_info;
890507c3241Smlf struct tgdk_geom phyg;
891507c3241Smlf
892507c3241Smlf /* dadk_getphygeom always returns success */
893507c3241Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg);
894507c3241Smlf
895507c3241Smlf media_info.dki_lbsize = phyg.g_secsiz;
896507c3241Smlf media_info.dki_capacity = phyg.g_cap;
897507c3241Smlf media_info.dki_media_type = DK_FIXED_DISK;
898507c3241Smlf
899507c3241Smlf if (ddi_copyout(&media_info, (void *)arg,
900507c3241Smlf sizeof (struct dk_minfo), flag)) {
901507c3241Smlf return (EFAULT);
902507c3241Smlf } else {
903507c3241Smlf return (0);
904507c3241Smlf }
905507c3241Smlf }
906507c3241Smlf
907507c3241Smlf case DKIOCINFO: {
908507c3241Smlf struct dk_cinfo *info = (struct dk_cinfo *)data;
909507c3241Smlf
910507c3241Smlf /* controller information */
911507c3241Smlf info->dki_ctype = (DKTP_EXT->tg_ctype);
912507c3241Smlf info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip));
913507c3241Smlf (void) strcpy(info->dki_cname,
914507c3241Smlf ddi_get_name(ddi_get_parent(dkp->dk_dip)));
915507c3241Smlf
916507c3241Smlf /* Unit Information */
917507c3241Smlf info->dki_unit = ddi_get_instance(dkp->dk_dip);
918507c3241Smlf devp = ddi_get_driver_private(dkp->dk_dip);
919507c3241Smlf info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp);
920507c3241Smlf (void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip));
921507c3241Smlf info->dki_flags = DKI_FMTVOL;
922507c3241Smlf info->dki_partition = CMDKPART(dev);
923507c3241Smlf
924507c3241Smlf info->dki_maxtransfer = maxphys / DEV_BSIZE;
925507c3241Smlf info->dki_addr = 1;
926507c3241Smlf info->dki_space = 0;
927507c3241Smlf info->dki_prio = 0;
928507c3241Smlf info->dki_vec = 0;
929507c3241Smlf
930507c3241Smlf if (ddi_copyout(data, (void *)arg, sizeof (*info), flag))
931507c3241Smlf return (EFAULT);
932507c3241Smlf else
933507c3241Smlf return (0);
934507c3241Smlf }
935507c3241Smlf
936507c3241Smlf case DKIOCSTATE: {
937507c3241Smlf int state;
938507c3241Smlf int rval;
939507c3241Smlf diskaddr_t p_lblksrt;
940507c3241Smlf diskaddr_t p_lblkcnt;
941507c3241Smlf
942507c3241Smlf if (ddi_copyin((void *)arg, &state, sizeof (int), flag))
943507c3241Smlf return (EFAULT);
944507c3241Smlf
945507c3241Smlf /* dadk_check_media blocks until state changes */
946507c3241Smlf if (rval = dadk_check_media(DKTP_DATA, &state))
947507c3241Smlf return (rval);
948507c3241Smlf
949507c3241Smlf if (state == DKIO_INSERTED) {
950507c3241Smlf
951e8fb11a1Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0)
952507c3241Smlf return (ENXIO);
953507c3241Smlf
954507c3241Smlf if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev),
955e8fb11a1Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0))
956507c3241Smlf return (ENXIO);
957507c3241Smlf
958507c3241Smlf if (p_lblkcnt <= 0)
959507c3241Smlf return (ENXIO);
960507c3241Smlf }
961507c3241Smlf
962507c3241Smlf if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag))
963507c3241Smlf return (EFAULT);
964507c3241Smlf
965507c3241Smlf return (0);
966507c3241Smlf }
967507c3241Smlf
968507c3241Smlf /*
969507c3241Smlf * is media removable?
970507c3241Smlf */
971507c3241Smlf case DKIOCREMOVABLE: {
972507c3241Smlf int i;
973507c3241Smlf
974507c3241Smlf i = (DKTP_EXT->tg_rmb) ? 1 : 0;
975507c3241Smlf
976507c3241Smlf if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag))
977507c3241Smlf return (EFAULT);
978507c3241Smlf
979507c3241Smlf return (0);
980507c3241Smlf }
981507c3241Smlf
982507c3241Smlf case DKIOCADDBAD:
983507c3241Smlf /*
984507c3241Smlf * This is not an update mechanism to add bad blocks
985507c3241Smlf * to the bad block structures stored on disk.
986507c3241Smlf *
987507c3241Smlf * addbadsec(1M) will update the bad block data on disk
988507c3241Smlf * and use this ioctl to force the driver to re-initialize
989507c3241Smlf * the list of bad blocks in the driver.
990507c3241Smlf */
991507c3241Smlf
992507c3241Smlf /* start BBH */
993507c3241Smlf cmdk_bbh_reopen(dkp);
994507c3241Smlf return (0);
995507c3241Smlf
996507c3241Smlf case DKIOCG_PHYGEOM:
997507c3241Smlf case DKIOCG_VIRTGEOM:
998507c3241Smlf case DKIOCGGEOM:
999507c3241Smlf case DKIOCSGEOM:
1000507c3241Smlf case DKIOCGAPART:
1001507c3241Smlf case DKIOCSAPART:
1002507c3241Smlf case DKIOCGVTOC:
1003507c3241Smlf case DKIOCSVTOC:
1004507c3241Smlf case DKIOCPARTINFO:
1005342440ecSPrasad Singamsetty case DKIOCGEXTVTOC:
1006342440ecSPrasad Singamsetty case DKIOCSEXTVTOC:
1007342440ecSPrasad Singamsetty case DKIOCEXTPARTINFO:
1008507c3241Smlf case DKIOCGMBOOT:
1009507c3241Smlf case DKIOCSMBOOT:
1010507c3241Smlf case DKIOCGETEFI:
1011507c3241Smlf case DKIOCSETEFI:
1012507c3241Smlf case DKIOCPARTITION:
1013aa1b14e7SSheshadri Vasudevan case DKIOCSETEXTPART:
1014507c3241Smlf {
1015507c3241Smlf int rc;
1016507c3241Smlf
1017e8fb11a1Sshidokht rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag,
1018e8fb11a1Sshidokht credp, rvalp, 0);
10193b22643dSJan Setje-Eilers if (cmd == DKIOCSVTOC || cmd == DKIOCSEXTVTOC)
1020507c3241Smlf cmdk_devid_setup(dkp);
1021507c3241Smlf return (rc);
1022507c3241Smlf }
1023507c3241Smlf
1024507c3241Smlf case DIOCTL_RWCMD: {
1025507c3241Smlf struct dadkio_rwcmd *rwcmdp;
1026507c3241Smlf int status;
1027507c3241Smlf
1028507c3241Smlf rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP);
1029507c3241Smlf
1030507c3241Smlf status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag);
1031507c3241Smlf
1032507c3241Smlf if (status == 0) {
1033507c3241Smlf bzero(&(rwcmdp->status), sizeof (struct dadkio_status));
1034507c3241Smlf status = dadk_ioctl(DKTP_DATA,
1035507c3241Smlf dev,
1036507c3241Smlf cmd,
1037507c3241Smlf (uintptr_t)rwcmdp,
1038507c3241Smlf flag,
1039507c3241Smlf credp,
1040507c3241Smlf rvalp);
1041507c3241Smlf }
1042507c3241Smlf if (status == 0)
1043507c3241Smlf status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag);
1044507c3241Smlf
1045507c3241Smlf kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd));
1046507c3241Smlf return (status);
1047507c3241Smlf }
1048507c3241Smlf
1049507c3241Smlf default:
1050507c3241Smlf return (dadk_ioctl(DKTP_DATA,
1051507c3241Smlf dev,
1052507c3241Smlf cmd,
1053507c3241Smlf arg,
1054507c3241Smlf flag,
1055507c3241Smlf credp,
1056507c3241Smlf rvalp));
1057507c3241Smlf }
1058507c3241Smlf }
1059507c3241Smlf
1060507c3241Smlf /*ARGSUSED1*/
1061507c3241Smlf static int
cmdkclose(dev_t dev,int flag,int otyp,cred_t * credp)1062507c3241Smlf cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp)
1063507c3241Smlf {
1064507c3241Smlf int part;
1065507c3241Smlf ulong_t partbit;
1066507c3241Smlf int instance;
1067507c3241Smlf struct cmdk *dkp;
1068507c3241Smlf int lastclose = 1;
1069507c3241Smlf int i;
1070507c3241Smlf
1071507c3241Smlf instance = CMDKUNIT(dev);
1072507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1073507c3241Smlf (otyp >= OTYPCNT))
1074507c3241Smlf return (ENXIO);
1075507c3241Smlf
1076507c3241Smlf mutex_enter(&dkp->dk_mutex);
1077507c3241Smlf
1078507c3241Smlf /* check if device has been opened */
107906bbe1e0Sedp ASSERT(cmdk_isopen(dkp, dev));
1080507c3241Smlf if (!(dkp->dk_flag & CMDK_OPEN)) {
1081507c3241Smlf mutex_exit(&dkp->dk_mutex);
1082507c3241Smlf return (ENXIO);
1083507c3241Smlf }
1084507c3241Smlf
10852df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) {
10862df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
10872df1fe9cSrandyf }
10882df1fe9cSrandyf
1089507c3241Smlf part = CMDKPART(dev);
1090507c3241Smlf partbit = 1 << part;
1091507c3241Smlf
1092507c3241Smlf /* account for close */
1093507c3241Smlf if (otyp == OTYP_LYR) {
109406bbe1e0Sedp ASSERT(dkp->dk_open_lyr[part] > 0);
1095507c3241Smlf if (dkp->dk_open_lyr[part])
1096507c3241Smlf dkp->dk_open_lyr[part]--;
109706bbe1e0Sedp } else {
109806bbe1e0Sedp ASSERT((dkp->dk_open_reg[otyp] & partbit) != 0);
1099507c3241Smlf dkp->dk_open_reg[otyp] &= ~partbit;
110006bbe1e0Sedp }
1101507c3241Smlf dkp->dk_open_exl &= ~partbit;
1102507c3241Smlf
1103507c3241Smlf for (i = 0; i < CMDK_MAXPART; i++)
1104507c3241Smlf if (dkp->dk_open_lyr[i] != 0) {
1105507c3241Smlf lastclose = 0;
1106507c3241Smlf break;
1107507c3241Smlf }
1108507c3241Smlf
1109507c3241Smlf if (lastclose)
1110507c3241Smlf for (i = 0; i < OTYPCNT; i++)
1111507c3241Smlf if (dkp->dk_open_reg[i] != 0) {
1112507c3241Smlf lastclose = 0;
1113507c3241Smlf break;
1114507c3241Smlf }
1115507c3241Smlf
1116507c3241Smlf mutex_exit(&dkp->dk_mutex);
1117507c3241Smlf
1118507c3241Smlf if (lastclose)
1119e8fb11a1Sshidokht cmlb_invalidate(dkp->dk_cmlbhandle, 0);
1120507c3241Smlf
1121507c3241Smlf return (DDI_SUCCESS);
1122507c3241Smlf }
1123507c3241Smlf
1124507c3241Smlf /*ARGSUSED3*/
1125507c3241Smlf static int
cmdkopen(dev_t * dev_p,int flag,int otyp,cred_t * credp)1126507c3241Smlf cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp)
1127507c3241Smlf {
1128507c3241Smlf dev_t dev = *dev_p;
1129507c3241Smlf int part;
1130507c3241Smlf ulong_t partbit;
1131507c3241Smlf int instance;
1132507c3241Smlf struct cmdk *dkp;
1133507c3241Smlf diskaddr_t p_lblksrt;
1134507c3241Smlf diskaddr_t p_lblkcnt;
1135507c3241Smlf int i;
1136507c3241Smlf int nodelay;
1137507c3241Smlf
1138507c3241Smlf instance = CMDKUNIT(dev);
1139507c3241Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
1140507c3241Smlf return (ENXIO);
1141507c3241Smlf
1142507c3241Smlf if (otyp >= OTYPCNT)
1143507c3241Smlf return (EINVAL);
1144507c3241Smlf
11452df1fe9cSrandyf mutex_enter(&dkp->dk_mutex);
11462df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) {
11472df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
11482df1fe9cSrandyf }
11492df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
11502df1fe9cSrandyf
1151507c3241Smlf part = CMDKPART(dev);
1152507c3241Smlf partbit = 1 << part;
1153507c3241Smlf nodelay = (flag & (FNDELAY | FNONBLOCK));
1154507c3241Smlf
1155507c3241Smlf mutex_enter(&dkp->dk_mutex);
1156507c3241Smlf
1157e8fb11a1Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) {
1158507c3241Smlf
1159507c3241Smlf /* fail if not doing non block open */
1160507c3241Smlf if (!nodelay) {
1161507c3241Smlf mutex_exit(&dkp->dk_mutex);
1162507c3241Smlf return (ENXIO);
1163507c3241Smlf }
1164507c3241Smlf } else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt,
1165e8fb11a1Sshidokht &p_lblksrt, NULL, NULL, 0) == 0) {
1166507c3241Smlf
1167507c3241Smlf if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) {
1168507c3241Smlf mutex_exit(&dkp->dk_mutex);
1169507c3241Smlf return (ENXIO);
1170507c3241Smlf }
1171507c3241Smlf } else {
1172507c3241Smlf /* fail if not doing non block open */
1173507c3241Smlf if (!nodelay) {
1174507c3241Smlf mutex_exit(&dkp->dk_mutex);
1175507c3241Smlf return (ENXIO);
1176507c3241Smlf }
1177507c3241Smlf }
1178507c3241Smlf
1179507c3241Smlf if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) {
1180507c3241Smlf mutex_exit(&dkp->dk_mutex);
1181507c3241Smlf return (EROFS);
1182507c3241Smlf }
1183507c3241Smlf
1184507c3241Smlf /* check for part already opend exclusively */
1185507c3241Smlf if (dkp->dk_open_exl & partbit)
1186507c3241Smlf goto excl_open_fail;
1187507c3241Smlf
1188507c3241Smlf /* check if we can establish exclusive open */
1189507c3241Smlf if (flag & FEXCL) {
1190507c3241Smlf if (dkp->dk_open_lyr[part])
1191507c3241Smlf goto excl_open_fail;
1192507c3241Smlf for (i = 0; i < OTYPCNT; i++) {
1193507c3241Smlf if (dkp->dk_open_reg[i] & partbit)
1194507c3241Smlf goto excl_open_fail;
1195507c3241Smlf }
1196507c3241Smlf }
1197507c3241Smlf
1198507c3241Smlf /* open will succeed, account for open */
1199507c3241Smlf dkp->dk_flag |= CMDK_OPEN;
1200507c3241Smlf if (otyp == OTYP_LYR)
1201507c3241Smlf dkp->dk_open_lyr[part]++;
1202507c3241Smlf else
1203507c3241Smlf dkp->dk_open_reg[otyp] |= partbit;
1204507c3241Smlf if (flag & FEXCL)
1205507c3241Smlf dkp->dk_open_exl |= partbit;
1206507c3241Smlf
1207507c3241Smlf mutex_exit(&dkp->dk_mutex);
1208507c3241Smlf return (DDI_SUCCESS);
1209507c3241Smlf
1210507c3241Smlf excl_open_fail:
1211507c3241Smlf mutex_exit(&dkp->dk_mutex);
1212507c3241Smlf return (EBUSY);
1213507c3241Smlf }
1214507c3241Smlf
1215507c3241Smlf /*
1216507c3241Smlf * read routine
1217507c3241Smlf */
1218507c3241Smlf /*ARGSUSED2*/
1219507c3241Smlf static int
cmdkread(dev_t dev,struct uio * uio,cred_t * credp)1220507c3241Smlf cmdkread(dev_t dev, struct uio *uio, cred_t *credp)
1221507c3241Smlf {
1222507c3241Smlf return (cmdkrw(dev, uio, B_READ));
1223507c3241Smlf }
1224507c3241Smlf
1225507c3241Smlf /*
1226507c3241Smlf * async read routine
1227507c3241Smlf */
1228507c3241Smlf /*ARGSUSED2*/
1229507c3241Smlf static int
cmdkaread(dev_t dev,struct aio_req * aio,cred_t * credp)1230507c3241Smlf cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp)
1231507c3241Smlf {
1232507c3241Smlf return (cmdkarw(dev, aio, B_READ));
1233507c3241Smlf }
1234507c3241Smlf
1235507c3241Smlf /*
1236507c3241Smlf * write routine
1237507c3241Smlf */
1238507c3241Smlf /*ARGSUSED2*/
1239507c3241Smlf static int
cmdkwrite(dev_t dev,struct uio * uio,cred_t * credp)1240507c3241Smlf cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp)
1241507c3241Smlf {
1242507c3241Smlf return (cmdkrw(dev, uio, B_WRITE));
1243507c3241Smlf }
1244507c3241Smlf
1245507c3241Smlf /*
1246507c3241Smlf * async write routine
1247507c3241Smlf */
1248507c3241Smlf /*ARGSUSED2*/
1249507c3241Smlf static int
cmdkawrite(dev_t dev,struct aio_req * aio,cred_t * credp)1250507c3241Smlf cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp)
1251507c3241Smlf {
1252507c3241Smlf return (cmdkarw(dev, aio, B_WRITE));
1253507c3241Smlf }
1254507c3241Smlf
1255507c3241Smlf static void
cmdkmin(struct buf * bp)1256507c3241Smlf cmdkmin(struct buf *bp)
1257507c3241Smlf {
1258507c3241Smlf if (bp->b_bcount > DK_MAXRECSIZE)
1259507c3241Smlf bp->b_bcount = DK_MAXRECSIZE;
1260507c3241Smlf }
1261507c3241Smlf
1262507c3241Smlf static int
cmdkrw(dev_t dev,struct uio * uio,int flag)1263507c3241Smlf cmdkrw(dev_t dev, struct uio *uio, int flag)
1264507c3241Smlf {
12652df1fe9cSrandyf int instance;
12662df1fe9cSrandyf struct cmdk *dkp;
12672df1fe9cSrandyf
12682df1fe9cSrandyf instance = CMDKUNIT(dev);
12692df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
12702df1fe9cSrandyf return (ENXIO);
12712df1fe9cSrandyf
12722df1fe9cSrandyf mutex_enter(&dkp->dk_mutex);
12732df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) {
12742df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
12752df1fe9cSrandyf }
12762df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
12772df1fe9cSrandyf
1278507c3241Smlf return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio));
1279507c3241Smlf }
1280507c3241Smlf
1281507c3241Smlf static int
cmdkarw(dev_t dev,struct aio_req * aio,int flag)1282507c3241Smlf cmdkarw(dev_t dev, struct aio_req *aio, int flag)
1283507c3241Smlf {
12842df1fe9cSrandyf int instance;
12852df1fe9cSrandyf struct cmdk *dkp;
12862df1fe9cSrandyf
12872df1fe9cSrandyf instance = CMDKUNIT(dev);
12882df1fe9cSrandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)))
12892df1fe9cSrandyf return (ENXIO);
12902df1fe9cSrandyf
12912df1fe9cSrandyf mutex_enter(&dkp->dk_mutex);
12922df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) {
12932df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
12942df1fe9cSrandyf }
12952df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
12962df1fe9cSrandyf
1297507c3241Smlf return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio));
1298507c3241Smlf }
1299507c3241Smlf
1300507c3241Smlf /*
1301507c3241Smlf * strategy routine
1302507c3241Smlf */
1303507c3241Smlf static int
cmdkstrategy(struct buf * bp)1304507c3241Smlf cmdkstrategy(struct buf *bp)
1305507c3241Smlf {
1306507c3241Smlf int instance;
1307507c3241Smlf struct cmdk *dkp;
1308507c3241Smlf long d_cnt;
1309507c3241Smlf diskaddr_t p_lblksrt;
1310507c3241Smlf diskaddr_t p_lblkcnt;
1311507c3241Smlf
1312507c3241Smlf instance = CMDKUNIT(bp->b_edev);
1313507c3241Smlf if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) ||
1314507c3241Smlf (dkblock(bp) < 0)) {
1315507c3241Smlf bp->b_resid = bp->b_bcount;
1316507c3241Smlf SETBPERR(bp, ENXIO);
1317507c3241Smlf biodone(bp);
1318507c3241Smlf return (0);
1319507c3241Smlf }
1320507c3241Smlf
13212df1fe9cSrandyf mutex_enter(&dkp->dk_mutex);
132206bbe1e0Sedp ASSERT(cmdk_isopen(dkp, bp->b_edev));
13232df1fe9cSrandyf while (dkp->dk_flag & CMDK_SUSPEND) {
13242df1fe9cSrandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex);
13252df1fe9cSrandyf }
13262df1fe9cSrandyf mutex_exit(&dkp->dk_mutex);
13272df1fe9cSrandyf
1328507c3241Smlf bp->b_flags &= ~(B_DONE|B_ERROR);
1329507c3241Smlf bp->b_resid = 0;
1330507c3241Smlf bp->av_back = NULL;
1331507c3241Smlf
1332507c3241Smlf /*
1333507c3241Smlf * only re-read the vtoc if necessary (force == FALSE)
1334507c3241Smlf */
1335e8fb11a1Sshidokht if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev),
1336e8fb11a1Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) {
1337507c3241Smlf SETBPERR(bp, ENXIO);
1338507c3241Smlf }
1339507c3241Smlf
1340507c3241Smlf if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt))
1341507c3241Smlf SETBPERR(bp, ENXIO);
1342507c3241Smlf
1343507c3241Smlf if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) {
1344507c3241Smlf bp->b_resid = bp->b_bcount;
1345507c3241Smlf biodone(bp);
1346507c3241Smlf return (0);
1347507c3241Smlf }
1348507c3241Smlf
1349507c3241Smlf d_cnt = bp->b_bcount >> SCTRSHFT;
1350507c3241Smlf if ((dkblock(bp) + d_cnt) > p_lblkcnt) {
1351507c3241Smlf bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT;
1352507c3241Smlf bp->b_bcount -= bp->b_resid;
1353507c3241Smlf }
1354507c3241Smlf
1355507c3241Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp))));
1356507c3241Smlf if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) {
1357507c3241Smlf bp->b_resid += bp->b_bcount;
1358507c3241Smlf biodone(bp);
1359507c3241Smlf }
1360507c3241Smlf return (0);
1361507c3241Smlf }
1362507c3241Smlf
1363507c3241Smlf static int
cmdk_create_obj(dev_info_t * dip,struct cmdk * dkp)1364507c3241Smlf cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp)
1365507c3241Smlf {
1366507c3241Smlf struct scsi_device *devp;
1367507c3241Smlf opaque_t queobjp = NULL;
1368507c3241Smlf opaque_t flcobjp = NULL;
1369507c3241Smlf char que_keyvalp[64];
1370507c3241Smlf int que_keylen;
1371507c3241Smlf char flc_keyvalp[64];
1372507c3241Smlf int flc_keylen;
1373507c3241Smlf
1374507c3241Smlf ASSERT(mutex_owned(&dkp->dk_mutex));
1375507c3241Smlf
1376507c3241Smlf /* Create linkage to queueing routines based on property */
1377507c3241Smlf que_keylen = sizeof (que_keyvalp);
1378507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1379507c3241Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1380507c3241Smlf DDI_PROP_SUCCESS) {
1381507c3241Smlf cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined");
1382507c3241Smlf return (DDI_FAILURE);
1383507c3241Smlf }
1384507c3241Smlf que_keyvalp[que_keylen] = (char)0;
1385507c3241Smlf
1386507c3241Smlf if (strcmp(que_keyvalp, "qfifo") == 0) {
1387507c3241Smlf queobjp = (opaque_t)qfifo_create();
1388507c3241Smlf } else if (strcmp(que_keyvalp, "qsort") == 0) {
1389507c3241Smlf queobjp = (opaque_t)qsort_create();
1390507c3241Smlf } else {
1391507c3241Smlf return (DDI_FAILURE);
1392507c3241Smlf }
1393507c3241Smlf
1394507c3241Smlf /* Create linkage to dequeueing routines based on property */
1395507c3241Smlf flc_keylen = sizeof (flc_keyvalp);
1396507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1397507c3241Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1398507c3241Smlf DDI_PROP_SUCCESS) {
1399507c3241Smlf cmn_err(CE_WARN,
1400507c3241Smlf "cmdk_create_obj: flow-control property undefined");
1401507c3241Smlf return (DDI_FAILURE);
1402507c3241Smlf }
1403507c3241Smlf
1404507c3241Smlf flc_keyvalp[flc_keylen] = (char)0;
1405507c3241Smlf
1406507c3241Smlf if (strcmp(flc_keyvalp, "dsngl") == 0) {
1407507c3241Smlf flcobjp = (opaque_t)dsngl_create();
1408507c3241Smlf } else if (strcmp(flc_keyvalp, "dmult") == 0) {
1409507c3241Smlf flcobjp = (opaque_t)dmult_create();
1410507c3241Smlf } else {
1411507c3241Smlf return (DDI_FAILURE);
1412507c3241Smlf }
1413507c3241Smlf
1414507c3241Smlf /* populate bbh_obj object stored in dkp */
1415507c3241Smlf dkp->dk_bbh_obj.bbh_data = dkp;
1416507c3241Smlf dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops;
1417507c3241Smlf
1418507c3241Smlf /* create linkage to dadk */
1419507c3241Smlf dkp->dk_tgobjp = (opaque_t)dadk_create();
1420507c3241Smlf
1421507c3241Smlf devp = ddi_get_driver_private(dip);
1422507c3241Smlf (void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj,
1423507c3241Smlf NULL);
1424507c3241Smlf
1425507c3241Smlf return (DDI_SUCCESS);
1426507c3241Smlf }
1427507c3241Smlf
1428507c3241Smlf static void
cmdk_destroy_obj(dev_info_t * dip,struct cmdk * dkp)1429507c3241Smlf cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp)
1430507c3241Smlf {
1431507c3241Smlf char que_keyvalp[64];
1432507c3241Smlf int que_keylen;
1433507c3241Smlf char flc_keyvalp[64];
1434507c3241Smlf int flc_keylen;
1435507c3241Smlf
1436507c3241Smlf ASSERT(mutex_owned(&dkp->dk_mutex));
1437507c3241Smlf
1438507c3241Smlf (void) dadk_free((dkp->dk_tgobjp));
1439507c3241Smlf dkp->dk_tgobjp = NULL;
1440507c3241Smlf
1441507c3241Smlf que_keylen = sizeof (que_keyvalp);
1442507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1443507c3241Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) !=
1444507c3241Smlf DDI_PROP_SUCCESS) {
1445507c3241Smlf cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined");
1446507c3241Smlf return;
1447507c3241Smlf }
1448507c3241Smlf que_keyvalp[que_keylen] = (char)0;
1449507c3241Smlf
1450507c3241Smlf flc_keylen = sizeof (flc_keyvalp);
1451507c3241Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF,
1452507c3241Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) !=
1453507c3241Smlf DDI_PROP_SUCCESS) {
1454507c3241Smlf cmn_err(CE_WARN,
1455507c3241Smlf "cmdk_destroy_obj: flow-control property undefined");
1456507c3241Smlf return;
1457507c3241Smlf }
1458507c3241Smlf flc_keyvalp[flc_keylen] = (char)0;
1459507c3241Smlf }
1460e8fb11a1Sshidokht /*ARGSUSED5*/
1461507c3241Smlf static int
cmdk_lb_rdwr(dev_info_t * dip,uchar_t cmd,void * bufaddr,diskaddr_t start,size_t count,void * tg_cookie)1462e8fb11a1Sshidokht cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr,
1463e8fb11a1Sshidokht diskaddr_t start, size_t count, void *tg_cookie)
1464507c3241Smlf {
1465507c3241Smlf struct cmdk *dkp;
1466507c3241Smlf opaque_t handle;
1467507c3241Smlf int rc = 0;
1468507c3241Smlf char *bufa;
1469de6d0fcdSShidokht Yadegari size_t buflen;
1470507c3241Smlf
1471507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1472507c3241Smlf if (dkp == NULL)
1473507c3241Smlf return (ENXIO);
1474507c3241Smlf
1475507c3241Smlf if (cmd != TG_READ && cmd != TG_WRITE)
1476507c3241Smlf return (EINVAL);
1477507c3241Smlf
1478de6d0fcdSShidokht Yadegari /* buflen must be multiple of 512 */
1479de6d0fcdSShidokht Yadegari buflen = (count + NBPSCTR - 1) & -NBPSCTR;
1480de6d0fcdSShidokht Yadegari handle = dadk_iob_alloc(DKTP_DATA, start, buflen, KM_SLEEP);
1481507c3241Smlf if (!handle)
1482507c3241Smlf return (ENOMEM);
1483507c3241Smlf
1484507c3241Smlf if (cmd == TG_READ) {
1485507c3241Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1486507c3241Smlf if (!bufa)
1487507c3241Smlf rc = EIO;
1488507c3241Smlf else
1489507c3241Smlf bcopy(bufa, bufaddr, count);
1490507c3241Smlf } else {
1491507c3241Smlf bufa = dadk_iob_htoc(DKTP_DATA, handle);
1492507c3241Smlf bcopy(bufaddr, bufa, count);
1493507c3241Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1494507c3241Smlf if (!bufa)
1495507c3241Smlf rc = EIO;
1496507c3241Smlf }
1497507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle);
1498507c3241Smlf
1499507c3241Smlf return (rc);
1500507c3241Smlf }
1501507c3241Smlf
1502e8fb11a1Sshidokht /*ARGSUSED3*/
1503507c3241Smlf static int
cmdk_lb_getinfo(dev_info_t * dip,int cmd,void * arg,void * tg_cookie)1504e8fb11a1Sshidokht cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
1505507c3241Smlf {
1506e8fb11a1Sshidokht
1507507c3241Smlf struct cmdk *dkp;
1508507c3241Smlf struct tgdk_geom phyg;
1509507c3241Smlf
1510e8fb11a1Sshidokht
1511507c3241Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip));
1512507c3241Smlf if (dkp == NULL)
1513507c3241Smlf return (ENXIO);
1514507c3241Smlf
1515e8fb11a1Sshidokht switch (cmd) {
1516e8fb11a1Sshidokht case TG_GETPHYGEOM: {
1517e8fb11a1Sshidokht cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg;
1518e8fb11a1Sshidokht
1519507c3241Smlf /* dadk_getphygeom always returns success */
1520507c3241Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg);
1521507c3241Smlf
1522e8fb11a1Sshidokht phygeomp->g_capacity = phyg.g_cap;
1523e8fb11a1Sshidokht phygeomp->g_nsect = phyg.g_sec;
1524e8fb11a1Sshidokht phygeomp->g_nhead = phyg.g_head;
1525e8fb11a1Sshidokht phygeomp->g_acyl = phyg.g_acyl;
1526e8fb11a1Sshidokht phygeomp->g_ncyl = phyg.g_cyl;
1527e8fb11a1Sshidokht phygeomp->g_secsize = phyg.g_secsiz;
1528e8fb11a1Sshidokht phygeomp->g_intrlv = 1;
1529e8fb11a1Sshidokht phygeomp->g_rpm = 3600;
1530507c3241Smlf
1531507c3241Smlf return (0);
1532507c3241Smlf }
1533507c3241Smlf
1534e8fb11a1Sshidokht case TG_GETVIRTGEOM: {
1535e8fb11a1Sshidokht cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg;
1536507c3241Smlf diskaddr_t capacity;
1537507c3241Smlf
1538507c3241Smlf (void) dadk_getgeom(DKTP_DATA, &phyg);
1539507c3241Smlf capacity = phyg.g_cap;
1540507c3241Smlf
1541507c3241Smlf /*
1542507c3241Smlf * If the controller returned us something that doesn't
1543507c3241Smlf * really fit into an Int 13/function 8 geometry
1544507c3241Smlf * result, just fail the ioctl. See PSARC 1998/313.
1545507c3241Smlf */
1546507c3241Smlf if (capacity < 0 || capacity >= 63 * 254 * 1024)
1547507c3241Smlf return (EINVAL);
1548507c3241Smlf
1549507c3241Smlf virtgeomp->g_capacity = capacity;
1550507c3241Smlf virtgeomp->g_nsect = 63;
1551507c3241Smlf virtgeomp->g_nhead = 254;
1552507c3241Smlf virtgeomp->g_ncyl = capacity / (63 * 254);
1553507c3241Smlf virtgeomp->g_acyl = 0;
1554507c3241Smlf virtgeomp->g_secsize = 512;
1555507c3241Smlf virtgeomp->g_intrlv = 1;
1556507c3241Smlf virtgeomp->g_rpm = 3600;
1557507c3241Smlf
1558507c3241Smlf return (0);
1559507c3241Smlf }
1560507c3241Smlf
1561e8fb11a1Sshidokht case TG_GETCAPACITY:
1562e8fb11a1Sshidokht case TG_GETBLOCKSIZE:
1563507c3241Smlf {
1564507c3241Smlf
1565507c3241Smlf /* dadk_getphygeom always returns success */
1566507c3241Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg);
1567e8fb11a1Sshidokht if (cmd == TG_GETCAPACITY)
1568e8fb11a1Sshidokht *(diskaddr_t *)arg = phyg.g_cap;
1569e8fb11a1Sshidokht else
1570e8fb11a1Sshidokht *(uint32_t *)arg = (uint32_t)phyg.g_secsiz;
1571507c3241Smlf
1572507c3241Smlf return (0);
1573507c3241Smlf }
1574507c3241Smlf
1575e8fb11a1Sshidokht case TG_GETATTR: {
1576e8fb11a1Sshidokht tg_attribute_t *tgattribute = (tg_attribute_t *)arg;
1577507c3241Smlf if ((DKTP_EXT->tg_rdonly))
1578507c3241Smlf tgattribute->media_is_writable = FALSE;
1579507c3241Smlf else
1580507c3241Smlf tgattribute->media_is_writable = TRUE;
1581*5cd2e4b9SYuri Pankov tgattribute->media_is_rotational = TRUE;
1582507c3241Smlf
1583507c3241Smlf return (0);
1584507c3241Smlf }
1585507c3241Smlf
1586e8fb11a1Sshidokht default:
1587e8fb11a1Sshidokht return (ENOTTY);
1588e8fb11a1Sshidokht }
1589e8fb11a1Sshidokht }
1590e8fb11a1Sshidokht
1591e8fb11a1Sshidokht
1592e8fb11a1Sshidokht
1593e8fb11a1Sshidokht
1594e8fb11a1Sshidokht
1595507c3241Smlf /*
1596507c3241Smlf * Create and register the devid.
1597507c3241Smlf * There are 4 different ways we can get a device id:
1598507c3241Smlf * 1. Already have one - nothing to do
1599507c3241Smlf * 2. Build one from the drive's model and serial numbers
1600507c3241Smlf * 3. Read one from the disk (first sector of last track)
1601507c3241Smlf * 4. Fabricate one and write it on the disk.
1602507c3241Smlf * If any of these succeeds, register the deviceid
1603507c3241Smlf */
1604507c3241Smlf static void
cmdk_devid_setup(struct cmdk * dkp)1605507c3241Smlf cmdk_devid_setup(struct cmdk *dkp)
1606507c3241Smlf {
1607507c3241Smlf int rc;
1608507c3241Smlf
1609507c3241Smlf /* Try options until one succeeds, or all have failed */
1610507c3241Smlf
1611507c3241Smlf /* 1. All done if already registered */
1612507c3241Smlf if (dkp->dk_devid != NULL)
1613507c3241Smlf return;
1614507c3241Smlf
1615507c3241Smlf /* 2. Build a devid from the model and serial number */
1616507c3241Smlf rc = cmdk_devid_modser(dkp);
1617507c3241Smlf if (rc != DDI_SUCCESS) {
1618507c3241Smlf /* 3. Read devid from the disk, if present */
1619507c3241Smlf rc = cmdk_devid_read(dkp);
1620507c3241Smlf
1621507c3241Smlf /* 4. otherwise make one up and write it on the disk */
1622507c3241Smlf if (rc != DDI_SUCCESS)
1623507c3241Smlf rc = cmdk_devid_fabricate(dkp);
1624507c3241Smlf }
1625507c3241Smlf
1626507c3241Smlf /* If we managed to get a devid any of the above ways, register it */
1627507c3241Smlf if (rc == DDI_SUCCESS)
1628507c3241Smlf (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid);
1629507c3241Smlf
1630507c3241Smlf }
1631507c3241Smlf
1632507c3241Smlf /*
1633507c3241Smlf * Build a devid from the model and serial number
1634507c3241Smlf * Return DDI_SUCCESS or DDI_FAILURE.
1635507c3241Smlf */
1636507c3241Smlf static int
cmdk_devid_modser(struct cmdk * dkp)1637507c3241Smlf cmdk_devid_modser(struct cmdk *dkp)
1638507c3241Smlf {
1639507c3241Smlf int rc = DDI_FAILURE;
1640507c3241Smlf char *hwid;
1641507c3241Smlf int modlen;
1642507c3241Smlf int serlen;
1643507c3241Smlf
1644507c3241Smlf /*
1645507c3241Smlf * device ID is a concatenation of model number, '=', serial number.
1646507c3241Smlf */
1647507c3241Smlf hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP);
1648507c3241Smlf modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN);
1649507c3241Smlf if (modlen == 0) {
1650507c3241Smlf rc = DDI_FAILURE;
1651507c3241Smlf goto err;
1652507c3241Smlf }
1653507c3241Smlf hwid[modlen++] = '=';
1654507c3241Smlf serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL,
1655507c3241Smlf hwid + modlen, CMDK_HWIDLEN - modlen);
1656507c3241Smlf if (serlen == 0) {
1657507c3241Smlf rc = DDI_FAILURE;
1658507c3241Smlf goto err;
1659507c3241Smlf }
1660507c3241Smlf hwid[modlen + serlen] = 0;
1661507c3241Smlf
1662507c3241Smlf /* Initialize the device ID, trailing NULL not included */
1663507c3241Smlf rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen,
16643d510deaSMark Logan hwid, &dkp->dk_devid);
1665507c3241Smlf if (rc != DDI_SUCCESS) {
1666507c3241Smlf rc = DDI_FAILURE;
1667507c3241Smlf goto err;
1668507c3241Smlf }
1669507c3241Smlf
1670507c3241Smlf rc = DDI_SUCCESS;
1671507c3241Smlf
1672507c3241Smlf err:
1673507c3241Smlf kmem_free(hwid, CMDK_HWIDLEN);
1674507c3241Smlf return (rc);
1675507c3241Smlf }
1676507c3241Smlf
1677507c3241Smlf static int
cmdk_get_modser(struct cmdk * dkp,int ioccmd,char * buf,int len)1678507c3241Smlf cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len)
1679507c3241Smlf {
1680507c3241Smlf dadk_ioc_string_t strarg;
1681507c3241Smlf int rval;
1682507c3241Smlf char *s;
1683507c3241Smlf char ch;
1684507c3241Smlf boolean_t ret;
1685507c3241Smlf int i;
1686507c3241Smlf int tb;
1687507c3241Smlf
1688507c3241Smlf strarg.is_buf = buf;
1689507c3241Smlf strarg.is_size = len;
1690507c3241Smlf if (dadk_ioctl(DKTP_DATA,
1691507c3241Smlf dkp->dk_dev,
1692507c3241Smlf ioccmd,
1693507c3241Smlf (uintptr_t)&strarg,
1694507c3241Smlf FNATIVE | FKIOCTL,
1695507c3241Smlf NULL,
1696507c3241Smlf &rval) != 0)
1697507c3241Smlf return (0);
1698507c3241Smlf
1699507c3241Smlf /*
1700507c3241Smlf * valid model/serial string must contain a non-zero non-space
1701507c3241Smlf * trim trailing spaces/NULL
1702507c3241Smlf */
1703507c3241Smlf ret = B_FALSE;
1704507c3241Smlf s = buf;
1705507c3241Smlf for (i = 0; i < strarg.is_size; i++) {
1706507c3241Smlf ch = *s++;
1707507c3241Smlf if (ch != ' ' && ch != '\0')
1708507c3241Smlf tb = i + 1;
1709507c3241Smlf if (ch != ' ' && ch != '\0' && ch != '0')
1710507c3241Smlf ret = B_TRUE;
1711507c3241Smlf }
1712507c3241Smlf
1713507c3241Smlf if (ret == B_FALSE)
1714507c3241Smlf return (0);
1715507c3241Smlf
1716507c3241Smlf return (tb);
1717507c3241Smlf }
1718507c3241Smlf
1719507c3241Smlf /*
1720507c3241Smlf * Read a devid from on the first block of the last track of
1721507c3241Smlf * the last cylinder. Make sure what we read is a valid devid.
1722507c3241Smlf * Return DDI_SUCCESS or DDI_FAILURE.
1723507c3241Smlf */
1724507c3241Smlf static int
cmdk_devid_read(struct cmdk * dkp)1725507c3241Smlf cmdk_devid_read(struct cmdk *dkp)
1726507c3241Smlf {
1727507c3241Smlf diskaddr_t blk;
1728507c3241Smlf struct dk_devid *dkdevidp;
1729507c3241Smlf uint_t *ip;
1730507c3241Smlf int chksum;
1731507c3241Smlf int i, sz;
1732e4da943dSMark Logan tgdk_iob_handle handle = NULL;
1733507c3241Smlf int rc = DDI_FAILURE;
1734507c3241Smlf
1735e8fb11a1Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0))
1736507c3241Smlf goto err;
1737507c3241Smlf
1738507c3241Smlf /* read the devid */
1739507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1740507c3241Smlf if (handle == NULL)
1741507c3241Smlf goto err;
1742507c3241Smlf
1743507c3241Smlf dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1744507c3241Smlf if (dkdevidp == NULL)
1745507c3241Smlf goto err;
1746507c3241Smlf
1747507c3241Smlf /* Validate the revision */
1748507c3241Smlf if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) ||
1749507c3241Smlf (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB))
1750507c3241Smlf goto err;
1751507c3241Smlf
1752507c3241Smlf /* Calculate the checksum */
1753507c3241Smlf chksum = 0;
1754507c3241Smlf ip = (uint_t *)dkdevidp;
1755507c3241Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1756507c3241Smlf chksum ^= ip[i];
1757507c3241Smlf if (DKD_GETCHKSUM(dkdevidp) != chksum)
1758507c3241Smlf goto err;
1759507c3241Smlf
1760507c3241Smlf /* Validate the device id */
1761507c3241Smlf if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS)
1762507c3241Smlf goto err;
1763507c3241Smlf
1764507c3241Smlf /* keep a copy of the device id */
1765507c3241Smlf sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid);
1766507c3241Smlf dkp->dk_devid = kmem_alloc(sz, KM_SLEEP);
1767507c3241Smlf bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz);
1768507c3241Smlf
1769507c3241Smlf rc = DDI_SUCCESS;
1770507c3241Smlf
1771507c3241Smlf err:
1772507c3241Smlf if (handle != NULL)
1773507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle);
1774507c3241Smlf return (rc);
1775507c3241Smlf }
1776507c3241Smlf
1777507c3241Smlf /*
1778507c3241Smlf * Create a devid and write it on the first block of the last track of
1779507c3241Smlf * the last cylinder.
1780507c3241Smlf * Return DDI_SUCCESS or DDI_FAILURE.
1781507c3241Smlf */
1782507c3241Smlf static int
cmdk_devid_fabricate(struct cmdk * dkp)1783507c3241Smlf cmdk_devid_fabricate(struct cmdk *dkp)
1784507c3241Smlf {
1785507c3241Smlf ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */
1786507c3241Smlf struct dk_devid *dkdevidp; /* devid struct stored on disk */
1787507c3241Smlf diskaddr_t blk;
1788507c3241Smlf tgdk_iob_handle handle = NULL;
1789507c3241Smlf uint_t *ip, chksum;
1790507c3241Smlf int i;
17913d510deaSMark Logan int rc = DDI_FAILURE;
1792507c3241Smlf
17933d510deaSMark Logan if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) !=
17943d510deaSMark Logan DDI_SUCCESS)
1795507c3241Smlf goto err;
1796507c3241Smlf
1797e8fb11a1Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) {
1798507c3241Smlf /* no device id block address */
17993d510deaSMark Logan goto err;
1800507c3241Smlf }
1801507c3241Smlf
1802507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP);
1803507c3241Smlf if (!handle)
1804507c3241Smlf goto err;
1805507c3241Smlf
1806507c3241Smlf /* Locate the buffer */
1807507c3241Smlf dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle);
1808507c3241Smlf
1809507c3241Smlf /* Fill in the revision */
1810507c3241Smlf bzero(dkdevidp, NBPSCTR);
1811507c3241Smlf dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB;
1812507c3241Smlf dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB;
1813507c3241Smlf
1814507c3241Smlf /* Copy in the device id */
1815507c3241Smlf i = ddi_devid_sizeof(devid);
1816507c3241Smlf if (i > DK_DEVID_SIZE)
1817507c3241Smlf goto err;
1818507c3241Smlf bcopy(devid, dkdevidp->dkd_devid, i);
1819507c3241Smlf
1820507c3241Smlf /* Calculate the chksum */
1821507c3241Smlf chksum = 0;
1822507c3241Smlf ip = (uint_t *)dkdevidp;
1823507c3241Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++)
1824507c3241Smlf chksum ^= ip[i];
1825507c3241Smlf
1826507c3241Smlf /* Fill in the checksum */
1827507c3241Smlf DKD_FORMCHKSUM(chksum, dkdevidp);
1828507c3241Smlf
1829507c3241Smlf /* write the devid */
1830507c3241Smlf (void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE);
1831507c3241Smlf
1832507c3241Smlf dkp->dk_devid = devid;
1833507c3241Smlf
1834507c3241Smlf rc = DDI_SUCCESS;
1835507c3241Smlf
1836507c3241Smlf err:
1837507c3241Smlf if (handle != NULL)
1838507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle);
1839507c3241Smlf
1840507c3241Smlf if (rc != DDI_SUCCESS && devid != NULL)
1841507c3241Smlf ddi_devid_free(devid);
1842507c3241Smlf
1843507c3241Smlf return (rc);
1844507c3241Smlf }
1845507c3241Smlf
1846507c3241Smlf static void
cmdk_bbh_free_alts(struct cmdk * dkp)1847507c3241Smlf cmdk_bbh_free_alts(struct cmdk *dkp)
1848507c3241Smlf {
1849507c3241Smlf if (dkp->dk_alts_hdl) {
1850507c3241Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1851507c3241Smlf kmem_free(dkp->dk_slc_cnt,
1852507c3241Smlf NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *)));
1853507c3241Smlf dkp->dk_alts_hdl = NULL;
1854507c3241Smlf }
1855507c3241Smlf }
1856507c3241Smlf
1857507c3241Smlf static void
cmdk_bbh_reopen(struct cmdk * dkp)1858507c3241Smlf cmdk_bbh_reopen(struct cmdk *dkp)
1859507c3241Smlf {
1860507c3241Smlf tgdk_iob_handle handle = NULL;
1861507c3241Smlf diskaddr_t slcb, slcn, slce;
1862507c3241Smlf struct alts_parttbl *ap;
1863507c3241Smlf struct alts_ent *enttblp;
1864507c3241Smlf uint32_t altused;
1865507c3241Smlf uint32_t altbase;
1866507c3241Smlf uint32_t altlast;
1867507c3241Smlf int alts;
1868507c3241Smlf uint16_t vtoctag;
1869507c3241Smlf int i, j;
1870507c3241Smlf
1871507c3241Smlf /* find slice with V_ALTSCTR tag */
1872507c3241Smlf for (alts = 0; alts < NDKMAP; alts++) {
1873507c3241Smlf if (cmlb_partinfo(
1874507c3241Smlf dkp->dk_cmlbhandle,
1875507c3241Smlf alts,
1876507c3241Smlf &slcn,
1877507c3241Smlf &slcb,
1878507c3241Smlf NULL,
1879e8fb11a1Sshidokht &vtoctag,
1880e8fb11a1Sshidokht 0)) {
1881507c3241Smlf goto empty; /* no partition table exists */
1882507c3241Smlf }
1883507c3241Smlf
1884507c3241Smlf if (vtoctag == V_ALTSCTR && slcn > 1)
1885507c3241Smlf break;
1886507c3241Smlf }
1887507c3241Smlf if (alts >= NDKMAP) {
1888507c3241Smlf goto empty; /* no V_ALTSCTR slice defined */
1889507c3241Smlf }
1890507c3241Smlf
1891507c3241Smlf /* read in ALTS label block */
1892507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP);
1893507c3241Smlf if (!handle) {
1894507c3241Smlf goto empty;
1895507c3241Smlf }
1896507c3241Smlf
1897507c3241Smlf ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1898507c3241Smlf if (!ap || (ap->alts_sanity != ALTS_SANITY)) {
1899507c3241Smlf goto empty;
1900507c3241Smlf }
1901507c3241Smlf
1902507c3241Smlf altused = ap->alts_ent_used; /* number of BB entries */
1903507c3241Smlf altbase = ap->alts_ent_base; /* blk offset from begin slice */
1904507c3241Smlf altlast = ap->alts_ent_end; /* blk offset to last block */
1905507c3241Smlf /* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */
1906507c3241Smlf
1907507c3241Smlf if (altused == 0 ||
1908507c3241Smlf altbase < 1 ||
1909507c3241Smlf altbase > altlast ||
1910507c3241Smlf altlast >= slcn) {
1911507c3241Smlf goto empty;
1912507c3241Smlf }
1913507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle);
1914507c3241Smlf
1915507c3241Smlf /* read in ALTS remapping table */
1916507c3241Smlf handle = dadk_iob_alloc(DKTP_DATA,
1917507c3241Smlf slcb + altbase,
1918507c3241Smlf (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP);
1919507c3241Smlf if (!handle) {
1920507c3241Smlf goto empty;
1921507c3241Smlf }
1922507c3241Smlf
1923507c3241Smlf enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ);
1924507c3241Smlf if (!enttblp) {
1925507c3241Smlf goto empty;
1926507c3241Smlf }
1927507c3241Smlf
1928507c3241Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1929507c3241Smlf
1930507c3241Smlf /* allocate space for dk_slc_cnt and dk_slc_ent tables */
1931507c3241Smlf if (dkp->dk_slc_cnt == NULL) {
1932507c3241Smlf dkp->dk_slc_cnt = kmem_alloc(NDKMAP *
1933507c3241Smlf (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP);
1934507c3241Smlf }
1935507c3241Smlf dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP);
1936507c3241Smlf
1937507c3241Smlf /* free previous BB table (if any) */
1938507c3241Smlf if (dkp->dk_alts_hdl) {
1939507c3241Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1940507c3241Smlf dkp->dk_alts_hdl = NULL;
1941507c3241Smlf dkp->dk_altused = 0;
1942507c3241Smlf }
1943507c3241Smlf
1944507c3241Smlf /* save linkage to new BB table */
1945507c3241Smlf dkp->dk_alts_hdl = handle;
1946507c3241Smlf dkp->dk_altused = altused;
1947507c3241Smlf
1948507c3241Smlf /*
1949507c3241Smlf * build indexes to BB table by slice
1950507c3241Smlf * effectively we have
1951507c3241Smlf * struct alts_ent *enttblp[altused];
1952507c3241Smlf *
1953507c3241Smlf * uint32_t dk_slc_cnt[NDKMAP];
1954507c3241Smlf * struct alts_ent *dk_slc_ent[NDKMAP];
1955507c3241Smlf */
1956507c3241Smlf for (i = 0; i < NDKMAP; i++) {
1957507c3241Smlf if (cmlb_partinfo(
1958507c3241Smlf dkp->dk_cmlbhandle,
1959507c3241Smlf i,
1960507c3241Smlf &slcn,
1961507c3241Smlf &slcb,
1962507c3241Smlf NULL,
1963e8fb11a1Sshidokht NULL,
1964e8fb11a1Sshidokht 0)) {
1965507c3241Smlf goto empty1;
1966507c3241Smlf }
1967507c3241Smlf
1968507c3241Smlf dkp->dk_slc_cnt[i] = 0;
1969507c3241Smlf if (slcn == 0)
1970507c3241Smlf continue; /* slice is not allocated */
1971507c3241Smlf
1972507c3241Smlf /* last block in slice */
1973507c3241Smlf slce = slcb + slcn - 1;
1974507c3241Smlf
1975507c3241Smlf /* find first remap entry in after beginnning of slice */
1976507c3241Smlf for (j = 0; j < altused; j++) {
1977507c3241Smlf if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb)
1978507c3241Smlf break;
1979507c3241Smlf }
1980507c3241Smlf dkp->dk_slc_ent[i] = enttblp + j;
1981507c3241Smlf
1982507c3241Smlf /* count remap entrys until end of slice */
1983507c3241Smlf for (; j < altused && enttblp[j].bad_start <= slce; j++) {
1984507c3241Smlf dkp->dk_slc_cnt[i] += 1;
1985507c3241Smlf }
1986507c3241Smlf }
1987507c3241Smlf
1988507c3241Smlf rw_exit(&dkp->dk_bbh_mutex);
1989507c3241Smlf return;
1990507c3241Smlf
1991507c3241Smlf empty:
1992507c3241Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER);
1993507c3241Smlf empty1:
1994507c3241Smlf if (handle && handle != dkp->dk_alts_hdl)
1995507c3241Smlf (void) dadk_iob_free(DKTP_DATA, handle);
1996507c3241Smlf
1997507c3241Smlf if (dkp->dk_alts_hdl) {
1998507c3241Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl);
1999507c3241Smlf dkp->dk_alts_hdl = NULL;
2000507c3241Smlf }
2001507c3241Smlf
2002507c3241Smlf rw_exit(&dkp->dk_bbh_mutex);
2003507c3241Smlf }
2004507c3241Smlf
2005507c3241Smlf /*ARGSUSED*/
2006507c3241Smlf static bbh_cookie_t
cmdk_bbh_htoc(opaque_t bbh_data,opaque_t handle)2007507c3241Smlf cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle)
2008507c3241Smlf {
2009507c3241Smlf struct bbh_handle *hp;
2010507c3241Smlf bbh_cookie_t ckp;
2011507c3241Smlf
2012507c3241Smlf hp = (struct bbh_handle *)handle;
2013507c3241Smlf ckp = hp->h_cktab + hp->h_idx;
2014507c3241Smlf hp->h_idx++;
2015507c3241Smlf return (ckp);
2016507c3241Smlf }
2017507c3241Smlf
2018507c3241Smlf /*ARGSUSED*/
2019507c3241Smlf static void
cmdk_bbh_freehandle(opaque_t bbh_data,opaque_t handle)2020507c3241Smlf cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle)
2021507c3241Smlf {
2022507c3241Smlf struct bbh_handle *hp;
2023507c3241Smlf
2024507c3241Smlf hp = (struct bbh_handle *)handle;
2025507c3241Smlf kmem_free(handle, (sizeof (struct bbh_handle) +
2026507c3241Smlf (hp->h_totck * (sizeof (struct bbh_cookie)))));
2027507c3241Smlf }
2028507c3241Smlf
2029507c3241Smlf
2030507c3241Smlf /*
2031507c3241Smlf * cmdk_bbh_gethandle remaps the bad sectors to alternates.
2032507c3241Smlf * There are 7 different cases when the comparison is made
2033507c3241Smlf * between the bad sector cluster and the disk section.
2034507c3241Smlf *
2035507c3241Smlf * bad sector cluster gggggggggggbbbbbbbggggggggggg
2036507c3241Smlf * case 1: ddddd
2037507c3241Smlf * case 2: -d-----
2038507c3241Smlf * case 3: ddddd
2039507c3241Smlf * case 4: dddddddddddd
2040507c3241Smlf * case 5: ddddddd-----
2041507c3241Smlf * case 6: ---ddddddd
2042507c3241Smlf * case 7: ddddddd
2043507c3241Smlf *
2044507c3241Smlf * where: g = good sector, b = bad sector
2045507c3241Smlf * d = sector in disk section
2046507c3241Smlf * - = disk section may be extended to cover those disk area
2047507c3241Smlf */
2048507c3241Smlf
2049507c3241Smlf static opaque_t
cmdk_bbh_gethandle(opaque_t bbh_data,struct buf * bp)2050507c3241Smlf cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp)
2051507c3241Smlf {
2052507c3241Smlf struct cmdk *dkp = (struct cmdk *)bbh_data;
2053507c3241Smlf struct bbh_handle *hp;
2054507c3241Smlf struct bbh_cookie *ckp;
2055507c3241Smlf struct alts_ent *altp;
2056507c3241Smlf uint32_t alts_used;
2057507c3241Smlf uint32_t part = CMDKPART(bp->b_edev);
2058507c3241Smlf daddr32_t lastsec;
2059507c3241Smlf long d_count;
2060507c3241Smlf int i;
2061507c3241Smlf int idx;
2062507c3241Smlf int cnt;
2063507c3241Smlf
2064507c3241Smlf if (part >= V_NUMPAR)
2065507c3241Smlf return (NULL);
2066507c3241Smlf
2067507c3241Smlf /*
2068507c3241Smlf * This if statement is atomic and it will succeed
2069507c3241Smlf * if there are no bad blocks (almost always)
2070507c3241Smlf *
2071507c3241Smlf * so this if is performed outside of the rw_enter for speed
2072507c3241Smlf * and then repeated inside the rw_enter for safety
2073507c3241Smlf */
2074507c3241Smlf if (!dkp->dk_alts_hdl) {
2075507c3241Smlf return (NULL);
2076507c3241Smlf }
2077507c3241Smlf
2078507c3241Smlf rw_enter(&dkp->dk_bbh_mutex, RW_READER);
2079507c3241Smlf
2080507c3241Smlf if (dkp->dk_alts_hdl == NULL) {
2081507c3241Smlf rw_exit(&dkp->dk_bbh_mutex);
2082507c3241Smlf return (NULL);
2083507c3241Smlf }
2084507c3241Smlf
2085507c3241Smlf alts_used = dkp->dk_slc_cnt[part];
2086507c3241Smlf if (alts_used == 0) {
2087507c3241Smlf rw_exit(&dkp->dk_bbh_mutex);
2088507c3241Smlf return (NULL);
2089507c3241Smlf }
2090507c3241Smlf altp = dkp->dk_slc_ent[part];
2091507c3241Smlf
2092507c3241Smlf /*
2093507c3241Smlf * binary search for the largest bad sector index in the alternate
2094507c3241Smlf * entry table which overlaps or larger than the starting d_sec
2095507c3241Smlf */
2096507c3241Smlf i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp));
2097507c3241Smlf /* if starting sector is > the largest bad sector, return */
2098507c3241Smlf if (i == -1) {
2099507c3241Smlf rw_exit(&dkp->dk_bbh_mutex);
2100507c3241Smlf return (NULL);
2101507c3241Smlf }
2102507c3241Smlf /* i is the starting index. Set altp to the starting entry addr */
2103507c3241Smlf altp += i;
2104507c3241Smlf
2105507c3241Smlf d_count = bp->b_bcount >> SCTRSHFT;
2106507c3241Smlf lastsec = GET_BP_SEC(bp) + d_count - 1;
2107507c3241Smlf
2108507c3241Smlf /* calculate the number of bad sectors */
2109507c3241Smlf for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) {
2110507c3241Smlf if (lastsec < altp->bad_start)
2111507c3241Smlf break;
2112507c3241Smlf }
2113507c3241Smlf
2114507c3241Smlf if (!cnt) {
2115507c3241Smlf rw_exit(&dkp->dk_bbh_mutex);
2116507c3241Smlf return (NULL);
2117507c3241Smlf }
2118507c3241Smlf
2119507c3241Smlf /* calculate the maximum number of reserved cookies */
2120507c3241Smlf cnt <<= 1;
2121507c3241Smlf cnt++;
2122507c3241Smlf
2123507c3241Smlf /* allocate the handle */
2124507c3241Smlf hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) +
2125507c3241Smlf (cnt * sizeof (*ckp))), KM_SLEEP);
2126507c3241Smlf
2127507c3241Smlf hp->h_idx = 0;
2128507c3241Smlf hp->h_totck = cnt;
2129507c3241Smlf ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1);
2130507c3241Smlf ckp[0].ck_sector = GET_BP_SEC(bp);
2131507c3241Smlf ckp[0].ck_seclen = d_count;
2132507c3241Smlf
2133507c3241Smlf altp = dkp->dk_slc_ent[part];
2134507c3241Smlf altp += i;
2135507c3241Smlf for (idx = 0; i < alts_used; i++, altp++) {
2136507c3241Smlf /* CASE 1: */
2137507c3241Smlf if (lastsec < altp->bad_start)
2138507c3241Smlf break;
2139507c3241Smlf
2140507c3241Smlf /* CASE 3: */
2141507c3241Smlf if (ckp[idx].ck_sector > altp->bad_end)
2142507c3241Smlf continue;
2143507c3241Smlf
2144507c3241Smlf /* CASE 2 and 7: */
2145507c3241Smlf if ((ckp[idx].ck_sector >= altp->bad_start) &&
2146507c3241Smlf (lastsec <= altp->bad_end)) {
2147507c3241Smlf ckp[idx].ck_sector = altp->good_start +
2148507c3241Smlf ckp[idx].ck_sector - altp->bad_start;
2149507c3241Smlf break;
2150507c3241Smlf }
2151507c3241Smlf
2152507c3241Smlf /* at least one bad sector in our section. break it. */
2153507c3241Smlf /* CASE 5: */
2154507c3241Smlf if ((lastsec >= altp->bad_start) &&
2155507c3241Smlf (lastsec <= altp->bad_end)) {
2156507c3241Smlf ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1;
2157507c3241Smlf ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen;
2158507c3241Smlf ckp[idx+1].ck_sector = altp->good_start;
2159507c3241Smlf break;
2160507c3241Smlf }
2161507c3241Smlf /* CASE 6: */
2162507c3241Smlf if ((ckp[idx].ck_sector <= altp->bad_end) &&
2163507c3241Smlf (ckp[idx].ck_sector >= altp->bad_start)) {
2164507c3241Smlf ckp[idx+1].ck_seclen = ckp[idx].ck_seclen;
2165507c3241Smlf ckp[idx].ck_seclen = altp->bad_end -
2166507c3241Smlf ckp[idx].ck_sector + 1;
2167507c3241Smlf ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen;
2168507c3241Smlf ckp[idx].ck_sector = altp->good_start +
2169507c3241Smlf ckp[idx].ck_sector - altp->bad_start;
2170507c3241Smlf idx++;
2171507c3241Smlf ckp[idx].ck_sector = altp->bad_end + 1;
2172507c3241Smlf continue; /* check rest of section */
2173507c3241Smlf }
2174507c3241Smlf
2175507c3241Smlf /* CASE 4: */
2176507c3241Smlf ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector;
2177507c3241Smlf ckp[idx+1].ck_sector = altp->good_start;
2178507c3241Smlf ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1;
2179507c3241Smlf idx += 2;
2180507c3241Smlf ckp[idx].ck_sector = altp->bad_end + 1;
2181507c3241Smlf ckp[idx].ck_seclen = lastsec - altp->bad_end;
2182507c3241Smlf }
2183507c3241Smlf
2184507c3241Smlf rw_exit(&dkp->dk_bbh_mutex);
2185507c3241Smlf return ((opaque_t)hp);
2186507c3241Smlf }
2187507c3241Smlf
2188507c3241Smlf static int
cmdk_bbh_bsearch(struct alts_ent * buf,int cnt,daddr32_t key)2189507c3241Smlf cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key)
2190507c3241Smlf {
2191507c3241Smlf int i;
2192507c3241Smlf int ind;
2193507c3241Smlf int interval;
2194507c3241Smlf int mystatus = -1;
2195507c3241Smlf
2196507c3241Smlf if (!cnt)
2197507c3241Smlf return (mystatus);
2198507c3241Smlf
2199507c3241Smlf ind = 1; /* compiler complains about possible uninitialized var */
2200507c3241Smlf for (i = 1; i <= cnt; i <<= 1)
2201507c3241Smlf ind = i;
2202507c3241Smlf
2203507c3241Smlf for (interval = ind; interval; ) {
2204507c3241Smlf if ((key >= buf[ind-1].bad_start) &&
2205507c3241Smlf (key <= buf[ind-1].bad_end)) {
2206507c3241Smlf return (ind-1);
2207507c3241Smlf } else {
2208507c3241Smlf interval >>= 1;
2209507c3241Smlf if (key < buf[ind-1].bad_start) {
2210507c3241Smlf /* record the largest bad sector index */
2211507c3241Smlf mystatus = ind-1;
2212507c3241Smlf if (!interval)
2213507c3241Smlf break;
2214507c3241Smlf ind = ind - interval;
2215507c3241Smlf } else {
2216507c3241Smlf /*
2217507c3241Smlf * if key is larger than the last element
2218507c3241Smlf * then break
2219507c3241Smlf */
2220507c3241Smlf if ((ind == cnt) || !interval)
2221507c3241Smlf break;
2222507c3241Smlf if ((ind+interval) <= cnt)
2223507c3241Smlf ind += interval;
2224507c3241Smlf }
2225507c3241Smlf }
2226507c3241Smlf }
2227507c3241Smlf return (mystatus);
2228507c3241Smlf }
2229